/******************************************************************************
*
*                    Copyright by Centec Networks, 2022
*
*
*  File:    sys_at_eunit.c
*  date:    2023-05-16
*
*
*******************************************************************************/

#if defined(ARCTIC)
#if defined E_UNIT && (FEATURE_MODE == 0)

/****************************************************************************
*
* Header Files
*
****************************************************************************/

#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "ctc_macro.h"
#include "ctc_dtel.h"
#include "ctc_eunit.h"

#include "drv_api.h"
#include "sys_usw_opf.h"
#include "sys_usw_eunit.h"
#include "sys_usw_chip.h"
#include "sys_usw_interrupt.h"
#include "sys_usw_dmps.h"

/***************************************************************
 *
 *  Defines and Macros
 *
 ***************************************************************/

#define SYS_AT_EUNIT_MEM_NUM 8 /* 8 * 512 kB */
#define SYS_AT_EUNIT_MEM_SIZE 512 /* 512 kB */
#define SYS_AT_EUNIT_MEM_UNITS 1024 /* kB */
#define SYS_AT_EUNIT_REMOTE_BASE 0x8000000
#define SYS_AT_EUNIT_REMOTE_MASK 0x7FFFFFF
#define SYS_AT_EUNIT_MEM_BASE 0x01000000
#define SYS_AT_EUNIT_MEM_BASE1 0x09000000 /*for core1*/
#define SYS_AT_EUNIT_HW_ADDR_BASE 0x40000000
#define SYS_AT_EUNIT_MAX_HW_LOCK_ID 7
#define SYS_AT_EUNIT_PCI_BASE 0x1000000
#define SYS_EUNIT_TOTAL_SIZE  (4*1024*SYS_AT_EUNIT_MEM_UNITS) /*4M*/


#define SYS_AT_EUNIT_NUM_PER_CORE 4
#define SYS_AT_EUNIT_ID_MASK_PER_CORE 0x3
#define SYS_AT_EUNIT_ID_MASK(E_ID) ((E_ID) & SYS_AT_EUNIT_ID_MASK_PER_CORE)

#define EUNIT_FEATURE_STR_TSX "TSX"
#define EUNIT_FEATURE_STR_TEX "TEX"
#define EUNIT_FEATURE_STR_IFA "IFA"
#define EUNIT_FEATURE_STR_MOX "MOX"
#define EUNIT_FEATURE_STR_REMOTE_CFG "REMOTE CONFIG"
#define EUNIT_FEATURE_STR_LEARNING_AGING "LEARNING AGING"
#define EUNIT_FEATURE_STR_SENSOR_MONITOR "SENSOR MONITOR"

#define SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset) ((eunit_id) < SYS_AT_EUNIT_NUM_PER_CORE ? (offset) &= 0xFFFFFFF : ((offset) = ((offset) & 0xFFFFFFF) | SYS_AT_EUNIT_REMOTE_BASE))
#define SYS_AT_EUNIT_RING_NUM_PER_DMA_CTL 30
extern sys_usw_eunit_master_t* p_usw_eunit_master[CTC_MAX_LOCAL_CHIP_NUM_PP];


#define SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id) lchip = SYS_PP_BASE(lchip) + sys_at_eunit_get_pp_id_by_eunit_id(lchip, eunit_id)

/*
 * +----------+-----------+
 * | eunit_id |   memory  |
 * +----------+-----------+
 * |    0/4   |    2M     |
 * +----------+-----------+
 * |    1/5   |    1M     |
 * +----------+-----------+
 * |    2/6   |    0.5M   |
 * +----------+-----------+
 * |    3/7   |    0.5M   |
 * +----------+-----------+
 *
 *
*/
#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
#define SYS_AT_EUNIT_MEM_0 256 /*units:kB*/
#define SYS_AT_EUNIT_MEM_1 256 /*units:kB*/
#define SYS_AT_EUNIT_MEM_2 256 /*units:kB*/
#define SYS_AT_EUNIT_MEM_3 256 /*units:kB*/
#else
#define SYS_AT_EUNIT_MEM_0 1024 /*units:kB*/
#define SYS_AT_EUNIT_MEM_1 1024 /*units:kB*/
#define SYS_AT_EUNIT_MEM_2 1024 /*units:kB*/
#define SYS_AT_EUNIT_MEM_3 1024 /*units:kB*/
#endif

/*
default:
ECPUDMA0:
 ring 0/1 --> ECPU00
 ring 2/3 --> ECPU01

ECPUDMA1:
 ring 0/1 --> ECPU10
 ring 2/3 --> ECPU11
*/
#define SYS_AT_PER_DMA_CTL_RX_RING_NUM 8 /*default value*/
#define SYS_AT_PER_DMA_CTL_TX_RING_NUM 4 /*default value*/

#define SYS_AT_EUNIT_DMA0 0
#define SYS_AT_EUNIT_DMA1 1
#define SYS_AT_EUNIT_DMA0_TBL_BASE 30
#define SYS_AT_EUNIT_DMA1_TBL_BASE 60

#define SYS_AT_EUNIT_DMA_RESET_CHECK(lchip, dma_sel) \
    do{\
        EcpuDmaResetCtl_m dma_rst_ctl;\
        uint32 cmd;\
        cmd = DRV_IOR(EcpuDmaResetCtl_t, DRV_ENTRY_FLAG);\
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &dma_rst_ctl));\
        if (SYS_AT_EUNIT_DMA0 == dma_sel)\
        {\
            if (GetEcpuDmaResetCtl(V, cfgEcpu0DmaReset_f, &dma_rst_ctl))\
            {\
                return CTC_E_NONE;\
            }\
        }\
        else\
        {\
            if (GetEcpuDmaResetCtl(V, cfgEcpu1DmaReset_f, &dma_rst_ctl))\
            {\
                return CTC_E_NONE;\
            }\
        }\
    }while(0);\
    

enum sys_at_eunit_id_e
{
    SYS_AT_EUNIT_ID_0 = 0,
    SYS_AT_EUNIT_ID_1,
    SYS_AT_EUNIT_ID_2,
    SYS_AT_EUNIT_ID_3,
    SYS_AT_EUNIT_ID_4,
    SYS_AT_EUNIT_ID_5,
    SYS_AT_EUNIT_ID_6,
    SYS_AT_EUNIT_ID_7,

    SYS_AT_EUNIT_ID_MAX
};
typedef enum sys_at_eunit_id_e sys_at_eunit_id_t;

enum sys_at_eunit_intr_e
{
    SYS_AT_EUNIT_INTR_ID_ALIVE = 0,
    SYS_AT_EUNIT_INTR_ID_ERROR = 1,
    SYS_AT_EUNIT_INTR_ID_PTP_0 = 16,/*means different domain ptp from 2 eCPU*/
    SYS_AT_EUNIT_INTR_ID_PTP_1,
    SYS_AT_EUNIT_INTR_ID_SENSOR0 = 18,
    SYS_AT_EUNIT_INTR_ID_SENSOR1 = 19,
    SYS_AT_EUNIT_INTR_ID_SENSOR2 = 20,
    SYS_AT_EUNIT_INTR_ID_SENSOR3 = 21,
    SYS_AT_EUNIT_INTR_ID_SENSOR4 = 22,
    SYS_AT_EUNIT_INTR_ID_SENSOR5 = 23,
    SYS_AT_EUNIT_INTR_ID_SENSOR6 = 24,
    SYS_AT_EUNIT_INTR_ID_SENSOR7 = 25,
    SYS_AT_EUNIT_INTR_ID_SENSOR8 = 26,
    SYS_AT_EUNIT_INTR_ID_SENSOR9 = 27,
    SYS_AT_EUNIT_INTR_ID_SENSOR10 = 28,
    SYS_AT_EUNIT_INTR_ID_SENSOR11 = 29,
    SYS_AT_EUNIT_INTR_ID_TOD_CODE_READY = 30,

    SYS_AT_EUNIT_INTR_ID_MAX = 127
};
typedef enum sys_at_eunit_intr_e sys_at_eunit_intr_t;

enum sys_at_eunit_cfg_type_e
{
    /* internal use */
    SYS_AT_EUNIT_CFG_RMOTE_CFG,
    SYS_AT_EUNIT_CFG_PTP,    
    SYS_AT_EUNIT_TOD,
    SYS_AT_EUNIT_CFG_LEARNING_AGING,

    SYS_AT_EUNIT_CFG_RUN_STATUS,
    SYS_AT_EUNIT_CFG_DBG,
    SYS_AT_EUNIT_TBL_RW,
    SYS_AT_EUNIT_DMA_INFO,
    SYS_AT_EUNIT_IO_LOG,
    SYS_AT_EUNIT_MEM_INFO,
    SYS_AT_EUNIT_PORT_INFO,
    SYS_AT_EUNIT_DUMP_THREAD_INFO,
    SYS_AT_EUNIT_CFG_LED,
    SYS_AT_EUNIT_CFG_LED_MAPPING,
    SYS_AT_EUNIT_CFG_SENSOR_MONITOR,
    SYS_AT_EUNIT_CFG_HW_RESET,
    SYS_AT_EUNIT_CFG_app_status_CNT,
    SYS_AT_EUNIT_CFG_EMIC_VER,
    SYS_AT_EUNIT_CFG_CMD_INFO,

    SYS_AT_EUNIT_CFG_TYPE_MAX = CTC_EUNIT_CFG_TYPE_CUSTOM_BASE
};
typedef enum sys_at_eunit_cfg_type_e sys_at_eunit_cfg_type_t;

enum sys_at_eunit_feature_e
{
    SYS_AT_EUNIT_FEATURE_LED,
    SYS_AT_EUNIT_FEATURE_LED_MAPPING,
    SYS_AT_EUNIT_FEATURE_REMOTE_CFG,
    SYS_AT_EUNIT_FEATURE_SENSOR_MONITOR,
    SYS_AT_EUNIT_FEATURE_PTP_DOMAIN_0,
    SYS_AT_EUNIT_FEATURE_PTP_DOMAIN_1,
    SYS_AT_EUNIT_FEATURE_TOD,
    SYS_AT_EUNIT_FEATURE_LEARNING_AGING,

    SYS_AT_EUNIT_FEATURE_MAX
};
typedef enum sys_at_eunit_feature_e sys_at_eunit_feature_t;

enum sys_at_eunit_misc_ext_type_e
{
    SYS_AT_EUNIT_MISC_EXT_BOOT_INFO, /* bit 0-3: eunit_id, bit4-7: run_status, bit8-23: pp_bmp, bit24: dual_core_mode, bit25-31: reserved */
    SYS_AT_EUNIT_MISC_EXT_SWITCH_ID,
    SYS_AT_EUNIT_MISC_EXT_MEM_SIZE,

    SYS_AT_EUNIT_MISC_EXT_MAX = 7
};
typedef enum sys_at_eunit_misc_ext_type_e sys_at_eunit_misc_ext_type_t;

enum sys_at_eunit_misc_int_type_e
{
    SYS_AT_EUNIT_MISC_INT_FEATURES,
    SYS_AT_EUNIT_MISC_INT_FEATURES_ADDR,
    SYS_AT_EUNIT_MISC_INT_CMD_MEM_ADDR,
    SYS_AT_EUNIT_MISC_INT_DBG_BUF_ADDR,
    SYS_AT_EUNIT_MISC_INT_ALIVE_CNT,
    SYS_AT_EUNIT_MISC_INT_PTP_ADDR,
    SYS_AT_EUNIT_MISC_INT_MAX = 7
};
typedef enum sys_at_eunit_misc_int_type_e sys_at_eunit_misc_int_type_t;

/****************************************************************************
*
* struct definition
*
****************************************************************************/

typedef struct sys_at_eunit_header_s
{
    uint8   cpu_name[8];
    uint32  version;
    uint64  start_address;
    uint32  size;
    uint32  rsvd;
}sys_at_eunit_header_t;

typedef struct sys_at_eunit_boot_info_s
{
    uint32  boot_addr;
    uint32  size;
}sys_at_eunit_boot_info_t;

/****************************************************************************
*
* function declaration
*
****************************************************************************/

STATIC int32
_sys_at_eunit_read_mem(uint8 lchip, uint32 offset, uint32* value, uint32 len);

extern int32
drv_usw_chip_read_eunit_mem(uint8 lchip, uint32 pci_addr, uint32* data, int32 len);
extern int32
drv_usw_chip_write_eunit_mem(uint8 lchip, uint32 pci_addr, uint32* data, int32 len);
int32
sys_at_eunit_is_working(uint8 lchip, uint8 eunit_id, uint8* is_working);
STATIC int32
_sys_at_eunit_misc_ext_ctl_read(uint8 lchip, uint8 eunit_id, uint8 type, uint32* value);
STATIC int32
_sys_at_eunit_get_boot_addr(uint8 lchip, uint8 eunit_id, uint32* addr);

/****************************************************************************
 *
* function definition
*
*****************************************************************************/

STATIC uint32
_sys_at_eunit_get_fixed_boot_addr(uint8 lchip, uint8 eunit_id)
{
    uint8 id = 0;
    uint32 mem_size[4] = {SYS_AT_EUNIT_MEM_0, SYS_AT_EUNIT_MEM_1, SYS_AT_EUNIT_MEM_2, SYS_AT_EUNIT_MEM_3};
    uint32 size = 0;
    for (id = 0; id < SYS_AT_EUNIT_ID_MASK(eunit_id); id++)
    {
        size += (mem_size[id] * SYS_AT_EUNIT_MEM_UNITS);
    }
    return size + ((eunit_id >= SYS_AT_EUNIT_NUM_PER_CORE) ? SYS_AT_EUNIT_MEM_BASE1 : SYS_AT_EUNIT_MEM_BASE);
}
/*units:kB*/
STATIC uint32
_sys_at_eunit_get_fixed_boot_size(uint8 lchip, uint8 eunit_id)
{
    switch (SYS_AT_EUNIT_ID_MASK(eunit_id))
    {
        case SYS_AT_EUNIT_ID_0:
            return SYS_AT_EUNIT_MEM_0;
        case SYS_AT_EUNIT_ID_1:
            return SYS_AT_EUNIT_MEM_1;
        case SYS_AT_EUNIT_ID_2:
            return SYS_AT_EUNIT_MEM_2;
        default:
            return SYS_AT_EUNIT_MEM_3;
    }
}

STATIC int32
_sys_at_eunit_get_boot_info(uint8 lchip, uint8 eunit_id, ctc_eunit_install_t* p_eunit, sys_at_eunit_boot_info_t* p_boot_info)
{
    sys_at_eunit_header_t header;
    sal_file_t fp = NULL;
    uint64 boot_addr = 0;
    uint64 real_boot_addr = 0;
    uint64 hw_addr_base = SYS_AT_EUNIT_HW_ADDR_BASE;
    uint32 size = 0;
    //uint32 curr_cpu_addr = 0;
    //uint32 curr_cpu_size = 0;
    uint32 pre_cpu_boot_addr = 0;
    uint32 pre_cpu_size = 0;
    uint32 next_cpu_boot_addr = 0;
    uint32 next_cpu_size = 0;
    uint8 is_working = 0;
    char* eunit_name[] = {"ecpu00", "ecpu01", "ecpu10", "ecpu11"};

    /*1. get boot_addr & size */
    fp = sal_fopen(p_eunit->bin_file, "r");
    if (fp == NULL)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Cannot open file %s\n", p_eunit->bin_file);
        return CTC_E_INVALID_PARAM;
    }

    sal_fread((uint8*)&header, sizeof(sys_at_eunit_header_t), 1, fp);

    boot_addr = header.start_address;
    size      = header.size/SYS_AT_EUNIT_MEM_UNITS; /*KB*/

    sal_fclose(fp);

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "eunit_id:%d, start address:%"PRIu64", len:%dKB\n", eunit_id, boot_addr, size);

    /*2. check ecpu name  */
    if (sal_strncmp((const char*)header.cpu_name, eunit_name[SYS_AT_EUNIT_ID_MASK(eunit_id)], sal_strlen(eunit_name[SYS_AT_EUNIT_ID_MASK(eunit_id)])))
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Image not match\n");
        return CTC_E_INVALID_PARAM;
    }

    /* 3. address overlap check, current ecpu address can not overlap pre ecpu address or next ecpu address */
    if(SYS_AT_EUNIT_ID_MASK(eunit_id) > 0)
    {
        CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id-1, &is_working));
        if(is_working)
        {
            _sys_at_eunit_get_boot_addr(lchip, eunit_id-1, &pre_cpu_boot_addr);
            _sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id-1, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &pre_cpu_size);

            real_boot_addr = pre_cpu_boot_addr;
            real_boot_addr = (real_boot_addr + hw_addr_base) << 4;
            
            if(boot_addr < (real_boot_addr+pre_cpu_size*SYS_AT_EUNIT_MEM_UNITS) && pre_cpu_size!=0)
            {
                SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "eunit_id:%d wrong ecpu start address:%"PRIu64", size:%dKB", eunit_id, boot_addr, size);
                return CTC_E_INVALID_PARAM;
            }
        }
    }

    if(SYS_AT_EUNIT_ID_MASK(eunit_id) < 3)
    {
        CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id+1, &is_working));
        if(is_working)
        {
            _sys_at_eunit_get_boot_addr(lchip, eunit_id+1, &next_cpu_boot_addr);
            _sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id+1, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &next_cpu_size);
            
            real_boot_addr = next_cpu_boot_addr;
            real_boot_addr = (real_boot_addr + hw_addr_base) << 4;
            
            if((boot_addr+size*SYS_AT_EUNIT_MEM_UNITS) > real_boot_addr && next_cpu_size!=0)
            {
                SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "eunit_id:%d wrong ecpu start address:%"PRIu64", size:%dKB", eunit_id, boot_addr, size);
                return CTC_E_INVALID_PARAM;
            }
        }
    }

    if((eunit_id < SYS_AT_EUNIT_NUM_PER_CORE))
    {
        p_boot_info->boot_addr = boot_addr - (hw_addr_base << 4);
    }
    else
    {
        p_boot_info->boot_addr = boot_addr - (hw_addr_base << 4) - SYS_AT_EUNIT_MEM_BASE + SYS_AT_EUNIT_MEM_BASE1;
    }

    p_boot_info->size = size;
    
    return CTC_E_NONE;
}

uint8
sys_at_eunit_get_pp_id_by_eunit_id(uint8 lchip, uint8 eunit_id)
{
    return (eunit_id >= SYS_AT_EUNIT_NUM_PER_CORE) ? (SYS_PP_NUM(lchip) / 2) : 0;
}

/*
    trigger ecpu interrupt by eunit_id
*/
int32
sys_at_eunit_trigger_intr(uint8 lchip, uint8 eunit_id, uint8 id)
{
    uint32 cmd = 0;
    IntrExtCtl_m intr_ext;
    uint32 intr_vec[4];

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(IntrExtCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &intr_ext));
    GetIntrExtCtl(A, intrExtCtl_f, &intr_ext, intr_vec);
    CTC_BMP_SET(intr_vec, id);
    SetIntrExtCtl(A, intrExtCtl_f, &intr_ext, intr_vec);
    cmd = DRV_IOW(IntrExtCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &intr_ext));
    return CTC_E_NONE;
}

int32
sys_at_eunit_get_intr(uint8 lchip, uint8 eunit_id, uint8 id, uint8* is_en)
{
    uint32 cmd = 0;
    IntrExtCtl_m intr_ext;
    uint32 intr_vec[4];

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(IntrExtCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &intr_ext));
    GetIntrExtCtl(A, intrExtCtl_f, &intr_ext, intr_vec);
    *is_en = CTC_BMP_ISSET(intr_vec, id);
    return CTC_E_NONE;
}

/*
type : refer to sys_at_eunit_misc_ext_type_t
*/
STATIC int32
_sys_at_eunit_misc_ext_ctl_write(uint8 lchip, uint8 eunit_id, uint8 type, uint32 value)
{
    uint32 cmd = 0;
    uint32 tbl_id = (MiscExtInfo1_t - MiscExtInfo0_t) * type + MiscExtInfo0_t;
    uint32 tbl_idx = 0;
    MiscExtInfo0_m misc_ext; /*ECPU self Read Only, Other CPU R/W */

    sal_memset(&misc_ext, 0, sizeof(misc_ext));


    tbl_idx = SYS_AT_EUNIT_ID_MASK(eunit_id);
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);

    SetMiscExtInfo0(V, miscExtInfo0_f, &misc_ext, value);
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tbl_idx, DRV_CMD_PP_EN(cmd), &misc_ext));
    return CTC_E_NONE;
}

/*
type : refer to sys_at_eunit_misc_ext_type_t
*/
STATIC int32
_sys_at_eunit_misc_ext_ctl_read(uint8 lchip, uint8 eunit_id, uint8 type, uint32* value)
{
    uint32 cmd = 0;
    uint32 tbl_id = (MiscExtInfo1_t - MiscExtInfo0_t) * type + MiscExtInfo0_t;
    MiscExtInfo0_m misc_ext; /*ECPU self Read Only, Other CPU R/W */
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &misc_ext));
    *value = GetMiscExtInfo0(V, miscExtInfo0_f, &misc_ext);
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_misc_int_ctl_read(uint8 lchip, uint8 eunit_id, uint8 type, uint32* value)
{
    uint32 cmd = 0;
    uint32 tbl_id = (MiscIntInfo1_t - MiscIntInfo0_t) * type + MiscIntInfo0_t;
    MiscIntInfo0_m misc_int; /*ECPU self Read Only, Other CPU R/W */
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &misc_int));
    *value = GetMiscIntInfo0(V, miscIntInfo0_f, &misc_int);
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_is_reset(uint8 lchip, uint8 eunit_id, uint8* value)
{
    uint32 cmd = 0;
    uint32 rst_tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00ResetCtl_t, Ecpu01ResetCtl_t, Ecpu10ResetCtl_t, Ecpu11ResetCtl_t};
    Ecpu00ResetCtl_m rst_ctl;

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &rst_ctl));
    *value = GetEcpu00ResetCtl(V, cfgEcpuIntfReset_f, &rst_ctl) || GetEcpu00ResetCtl(V, cfgEcpuCoreReset_f, &rst_ctl);
    return CTC_E_NONE;
}

int32
sys_at_eunit_is_working(uint8 lchip, uint8 eunit_id, uint8* is_working)
{
    uint32 intr_vec[2] = {0};
	uint8 is_reset = 0;
    uint32 offset = 0;

    CTC_PTR_VALID_CHECK(is_working);
    CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, eunit_id, &is_reset));
    if (!is_reset)
    {
        CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_ALIVE_CNT, &offset));
        CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset), &intr_vec[0], 1));

        sal_task_sleep(50);

        CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset), &intr_vec[1], 1));

        *is_working = (intr_vec[0] != intr_vec[1]);
    }
    else
    {
        *is_working = 0;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_get_boot_addr(uint8 lchip, uint8 eunit_id, uint32* addr)
{
    uint32 cmd = 0;
    uint32 tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00BootAddr_t, Ecpu01BootAddr_t, Ecpu10BootAddr_t, Ecpu11BootAddr_t};
    Ecpu00BootAddr_m boot_addr;

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &boot_addr));
    *addr = GetEcpu00BootAddr(V, ecpuBootAddr_f, &boot_addr) & (~SYS_AT_EUNIT_HW_ADDR_BASE);
    return CTC_E_NONE;
}

/*1 word length*/
STATIC int32
_sys_at_eunit_write_data(uint8 lchip, uint32 offset, uint32 value)
{
    /*dal pcie write or memMap*/
    drv_usw_chip_write_eunit_mem(lchip, offset, &value, 1);
    return CTC_E_NONE;
}
/*1 word length*/
int32
_sys_at_eunit_read_data(uint8 lchip, uint32 offset, uint32* value)
{
    /*dal pcie read or memMap*/
    drv_usw_chip_read_eunit_mem(lchip, offset, value, 1);
    return CTC_E_NONE;
}

/*len: 4 bytes*/
STATIC int32
_sys_at_eunit_write_mem(uint8 lchip, uint32 offset, uint32* value, uint32 len)
{
    drv_usw_chip_write_eunit_mem(lchip, offset, value, len);
    return CTC_E_NONE;
}
/*len: 4 bytes*/
STATIC int32
_sys_at_eunit_read_mem(uint8 lchip, uint32 offset, uint32* value, uint32 len)
{
    drv_usw_chip_read_eunit_mem(lchip, offset, value, len);
    return CTC_E_NONE;
}

int32
_sys_at_eunit_load_file(uint8 lchip, uint32 boot_addr, char* file)
{
    char tmp[20];
    sal_file_t fp = NULL;
    uint32 offset = 0;
    uint32 value = 0;
    int32 ret = 0;

    fp = sal_fopen(file, "r");
    if (fp == NULL)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Cannot open file %s\n", file);
        return CTC_E_INVALID_PARAM;
    }

    ret = sal_fseek(fp, sizeof(sys_at_eunit_header_t), SEEK_SET);
    if(ret < 0)
    {
        sal_fclose(fp);
        return CTC_E_INVALID_PARAM;
    }

    while (sal_fgets(tmp, 20, fp) != NULL)
    {
        value = sal_strtou32(tmp, NULL, 16);
        _sys_at_eunit_write_data(lchip, boot_addr + offset * sizeof(uint32), value);
        offset++;
    }
    sal_fclose(fp);

    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_release_reset(uint8 lchip, uint8 eunit_id, uint32 addr, uint8 is_release)
{
    uint32 cmd = 0;
    uint32 rst_tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00ResetCtl_t, Ecpu01ResetCtl_t, Ecpu10ResetCtl_t, Ecpu11ResetCtl_t};
    uint32 boot_tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00BootAddr_t, Ecpu01BootAddr_t, Ecpu10BootAddr_t, Ecpu11BootAddr_t};
    uint32 clk_tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00EnClk_t, Ecpu01EnClk_t, Ecpu10EnClk_t, Ecpu11EnClk_t};
    Ecpu00BootAddr_m boot_addr;
    Ecpu00ResetCtl_m rst_ctl;
    Ecpu00EnClk_m clk_ctl;
    EcpuDmaEnClk_m dma_clk;
    EcpuInterruptNormal_m intr_nor;
    EcpuInitDone_m ecpu_init_done;
    EcpuInit_m ecpu_init;
    Grant0ExtMask_m extMask;
    uint16 shift = Grant1ExtMask_t - Grant0ExtMask_t;
    uint8 idx = 0;

    sal_memset(&boot_addr, 0, sizeof(boot_addr));
    sal_memset(&rst_ctl, 0, sizeof(rst_ctl));
    sal_memset(&clk_ctl, 0, sizeof(clk_ctl));
    sal_memset(&dma_clk, 0, sizeof(dma_clk));
    sal_memset(&ecpu_init_done, 0, sizeof(EcpuInitDone_m));
    sal_memset(&ecpu_init, 0, sizeof(EcpuInit_m));
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    cmd = DRV_IOR(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &rst_ctl));

    if (is_release)
    {
#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
{
        Ecpu00RtcDiv_m div_ctl;
        uint32 div_tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00RtcDiv_t, Ecpu01RtcDiv_t, Ecpu10RtcDiv_t, Ecpu11RtcDiv_t};
        SetEcpu00RtcDiv(V, cfgEcpuRtcDiv_f, &div_ctl, 25); /* 25MHz / 25 = 1MHz*/
        cmd = DRV_IOW(div_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &div_ctl));
}
#endif
        SetEcpu00EnClk(V, cfgEcpuCoreEnClk_f, &clk_ctl, 1);
        SetEcpu00EnClk(V, cfgEcpuIntfEnClk_f, &clk_ctl, 1);
        cmd = DRV_IOW(clk_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &clk_ctl));

        cmd = DRV_IOR(EcpuDmaEnClk_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &dma_clk));
        if(GetEcpuDmaEnClk(V, cfgEcpu0DmaEnClk_f+eunit_id/2, &dma_clk))
        {
            SetEcpuDmaEnClk(V, cfgEcpu0DmaEnClk_f, &dma_clk, 1);
            cmd = DRV_IOW(EcpuDmaEnClk_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &dma_clk));
        }

        if (eunit_id >= SYS_AT_EUNIT_NUM_PER_CORE)
        {
            SetEcpu00BootAddr(V, ecpuBootAddr_f, &boot_addr, ((addr - SYS_AT_EUNIT_MEM_BASE1 + SYS_AT_EUNIT_MEM_BASE) >> 4) | SYS_AT_EUNIT_HW_ADDR_BASE);
        }
        else
        {
            SetEcpu00BootAddr(V, ecpuBootAddr_f, &boot_addr, (addr >> 4) | SYS_AT_EUNIT_HW_ADDR_BASE);
        }
        cmd = DRV_IOW(boot_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &boot_addr));

        SetEcpu00ResetCtl(V, cfgEcpuIntfReset_f, &rst_ctl, 0);
        cmd = DRV_IOW(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &rst_ctl));

        /* mask Ecpu normal interrupt */
        sal_memset(&intr_nor, 0xff, sizeof(EcpuInterruptNormal_m));
        cmd = DRV_IOW(EcpuInterruptNormal_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, DRV_INS(SYS_AT_EUNIT_ID_MASK(eunit_id), 2), DRV_CMD_PP_EN(cmd), &intr_nor);

        /* clean Grantmask for hw-lock */
        sal_memset(&extMask, 0, sizeof(extMask));
        SetGrant0ExtMask(V, grant0ExtMask_f, &extMask, 0);
        for (idx = 0; idx < 7; idx++)
        {
            cmd = DRV_IOW(Grant0ExtMask_t + idx * shift, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, DRV_INS(SYS_AT_EUNIT_ID_MASK(eunit_id), 0), DRV_CMD_PP_EN(cmd), &extMask));
        }

        SetEcpu00ResetCtl(V, cfgEcpuCoreReset_f, &rst_ctl, 0);
        cmd = DRV_IOW(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &rst_ctl));
    }
    else
    {
        /* reset */
        SetEcpu00ResetCtl(V, cfgEcpuIntfReset_f, &rst_ctl, 1);
        SetEcpu00ResetCtl(V, cfgEcpuCoreReset_f, &rst_ctl, 1);
        cmd = DRV_IOW(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &rst_ctl));

        SetEcpu00BootAddr(V, ecpuBootAddr_f, &boot_addr, 0);
        cmd = DRV_IOW(boot_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &boot_addr));


        SetEcpu00EnClk(V, cfgEcpuCoreEnClk_f, &clk_ctl, 0);
        SetEcpu00EnClk(V, cfgEcpuIntfEnClk_f, &clk_ctl, 0);
        cmd = DRV_IOW(clk_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &clk_ctl));

        /*read anthoer eunit use or not use, if not use will disable dmaenclk*/
        cmd = DRV_IOR(rst_tbl_id[SYS_AT_EUNIT_ID_MASK((eunit_id%2==0)?(eunit_id+1):(eunit_id-1))], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &rst_ctl));
        if(1 == GetEcpu00ResetCtl(V, cfgEcpuCoreReset_f, &rst_ctl))
        {
            SetEcpuDmaEnClk(V, cfgEcpu0DmaEnClk_f+eunit_id/2, &dma_clk, 0);
            cmd = DRV_IOW(EcpuDmaEnClk_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &dma_clk));
        }
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_map_cfg_unit(uint8 lchip, uint8 cfg_type, uint8* eunit_id_bmp)
{
    uint32 value = 0;
    uint32 features = 0;
    uint8 e_id = 0;
    uint8 is_reset = 0;
    switch (cfg_type)
    {
	case SYS_EUNIT_CFG_PTP_DOMAIN_0:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_PTP_DOMAIN_0);
        break;
	case SYS_EUNIT_CFG_PTP_DOMAIN_1:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_PTP_DOMAIN_1);
        break;
    case SYS_EUNIT_CFG_LEARNING_AGING:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_LEARNING_AGING);
        break;
    case SYS_EUNIT_CFG_LED:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_LED);
        break;
    case SYS_EUNIT_CFG_LED_MAPPING:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_LED_MAPPING);
        break;
    case SYS_EUNIT_CFG_SENSOR_MONITOR:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_SENSOR_MONITOR);
        break;
    case SYS_EUNIT_CFG_HW_RESET:
    case SYS_EUNIT_CFG_APP_STATUS:    
        break;
    case SYS_EUNIT_CFG_TOD:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_TOD);
        break;
    default:
        return CTC_E_INVALID_PARAM;
    }
    for (e_id = 0; e_id < MCHIP_CAP(SYS_CAP_EUNIT_NUM); e_id++)
    {
        CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, e_id, &is_reset));
        if (is_reset)
        {
            continue;
        }
        CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, e_id, SYS_AT_EUNIT_MISC_INT_FEATURES, &value));
        if (value & features)
        {
            CTC_BIT_SET(*eunit_id_bmp, e_id);
            if (SYS_EUNIT_CFG_LEARNING_AGING == cfg_type)
            {
                p_usw_eunit_master[lchip]->eunit_la_id = e_id;
            }
        }
        if (SYS_EUNIT_CFG_HW_RESET == cfg_type)
        {
            CTC_BIT_SET(*eunit_id_bmp, e_id);
        }
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_map_isr(uint8 lchip, uint8 irq_id,  uint8* isr_type)
{
    switch (irq_id)
    {
        case SYS_AT_EUNIT_INTR_ID_ERROR:
            *isr_type = SYS_EUNIT_ISR_ERROR;
            break;
		 case SYS_AT_EUNIT_INTR_ID_PTP_0:
		 case SYS_AT_EUNIT_INTR_ID_PTP_1:
            *isr_type = SYS_EUNIT_ISR_PTP;
            break;
         case SYS_AT_EUNIT_INTR_ID_SENSOR0:
         case SYS_AT_EUNIT_INTR_ID_SENSOR1:
         case SYS_AT_EUNIT_INTR_ID_SENSOR2:
         case SYS_AT_EUNIT_INTR_ID_SENSOR3:
         case SYS_AT_EUNIT_INTR_ID_SENSOR4:
         case SYS_AT_EUNIT_INTR_ID_SENSOR5:
         case SYS_AT_EUNIT_INTR_ID_SENSOR6:
         case SYS_AT_EUNIT_INTR_ID_SENSOR7:
         case SYS_AT_EUNIT_INTR_ID_SENSOR8:
         case SYS_AT_EUNIT_INTR_ID_SENSOR9:
         case SYS_AT_EUNIT_INTR_ID_SENSOR10:
         case SYS_AT_EUNIT_INTR_ID_SENSOR11:
            *isr_type = SYS_EUNIT_ISR_SENSOR_MONITOR;
            break;
         case SYS_AT_EUNIT_INTR_ID_TOD_CODE_READY:
            *isr_type = SYS_EUNIT_ISR_TOD_CODE_READY;
            break;
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_map_misc_int_type(uint8 lchip, uint8 cfg_type, uint8* misc_int_type)
{
    switch (cfg_type)
    {
        case SYS_EUNIT_CFG_PTP_DOMAIN_0:
	    case SYS_EUNIT_CFG_PTP_DOMAIN_1:
            *misc_int_type = SYS_AT_EUNIT_MISC_INT_PTP_ADDR;
            break;
		default:
			return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}


STATIC int32
_sys_at_eunit_clear_irq_id(uint8 lchip, uint8 eunit_id, uint8 id)
{
    uint32 cmd = 0;
    uint32 value[4] = {0};
    IntrIntCtl_m intr_ctl;

    if (id > 127)
    {
        return CTC_E_INVALID_PARAM;
    }

    sal_memset(&intr_ctl, 0, sizeof(intr_ctl));
    CTC_BMP_SET(value, id);
    SetIntrIntCtl(A, intrIntCtl_f, &intr_ctl, value);
    cmd = DRV_IOW(IntrIntCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &intr_ctl));

    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_irq_dispatch(uint8 lchip, uint8 eunit_id, uint8 id)
{
    uint8 isr_type = 0;
    sys_usw_eunit_isr_data_t isr_data;

    _sys_at_eunit_map_isr(lchip, id, &isr_type);
    isr_data.unit = eunit_id;
    isr_data.irq_id = id;
    _sys_at_eunit_clear_irq_id(lchip, eunit_id, id);
    if (p_usw_eunit_master[lchip]->isr[isr_type])
    {
        p_usw_eunit_master[lchip]->isr[isr_type](lchip, isr_type, &isr_data);
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_get_data_base(uint8 lchip, uint8 eunit_id, uint32* offset)
{
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_CMD_MEM_ADDR, offset));
    SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, *offset);

    return CTC_E_NONE;
}


STATIC int32
_sys_at_eunit_get_app_status(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    uint8 eunit_id  = 0;
    uint32 base     = 0;
    uint32 offset   = 0;
    uint32 info_offset = 0;
    int32 ret = CTC_E_NONE;
    uint8 is_working;
    uint8 idx = 0;
    uint8 app_num = 0;
    ctc_eunit_status_t *app_status = NULL;
    sys_usw_eunit_keepalive_body_t keep_info;
    sys_usw_eunit_app_info_body_t app_info;
    sys_usw_eunit_app_info_hdr_t app_name_hdr;

    app_status = (ctc_eunit_status_t*)p_cfg;
    eunit_id = app_status->eunit_id;


    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }

    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_FEATURES_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset), (uint32*)&app_name_hdr, 1));
    app_num = app_name_hdr.app_num;

    for(idx = 0; idx<app_num; idx++)
    {
        info_offset = (offset + 4) + idx*sizeof(sys_usw_eunit_app_info_body_t);

        memset(&app_info, 0, sizeof(app_info));
        
        CTC_ERROR_GOTO(_sys_at_eunit_read_mem(lchip, info_offset, (uint32*)&app_info, sizeof(sys_usw_eunit_app_info_body_t)/4), ret, error_back);

        if(app_info.app_id == app_status->app_id)
        {
            break;
        }
    }

    if(idx == app_num)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "invalid app_id:%d\n", app_status->app_id);
        return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_ALIVE_CNT, &base));
    
    offset = (SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, base) + 4) + app_status->app_id*sizeof(sys_usw_eunit_keepalive_body_t); /*eunit_keepalive_body_t*/
    
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset, (uint32*)&keep_info, 1));
    
    app_status->alive_cnt = keep_info.alive_cnt;
    
error_back:
    return ret;
}

/* wait until ECPU take away this flag information */
STATIC int32
_sys_at_eunit_cfg_op_finish(uint8 lchip, uint8 eunit_id, uint32 offset)
{
    uint16 timeout = SYS_EUNIT_CMD_TIMEOUT;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};

    do
    {
        /* Get CMD Memory */
        CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
        if (cfg_cmd.done)
        {
            return CTC_E_NONE;
        }
        sal_task_sleep(1);
    }while (--timeout);
    return CTC_E_HW_FAIL;
}

STATIC int32
_sys_at_eunit_get_empty_cmd(uint8 lchip, uint32 offset, sys_eunit_cfg_cmd_t* cfg_cmd)
{
    uint16 timeout = SYS_EUNIT_CMD_TIMEOUT;
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset, (uint32*)cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    while (cfg_cmd->valid && --timeout)
    {
        sal_task_sleep(1);
        CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset, (uint32*)cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    }
    if (cfg_cmd->valid)
    {
        return CTC_E_HW_FAIL;
    }
    return CTC_E_NONE;
}
STATIC int32
_sys_at_eunit_set_boot_info(uint8 lchip, uint8 eunit_id)
{
    uint32 boot_info = 0;
    uint8 dual_core_mode = 0;
    uint16 pp_bmp = drv_vchip_get_pp_bmp(lchip);

    dual_core_mode = (drv_vchip_get_core_num(lchip) > 1) ? 1 : 0;
    boot_info = (eunit_id & 0xF) | (SYS_EUNIT_RUN_STATUS_RUNNING << 4) | (pp_bmp << 8) | (dual_core_mode << 24);
    CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_write(lchip, eunit_id,
                                                          SYS_AT_EUNIT_MISC_EXT_BOOT_INFO,
                                                          boot_info));
    return CTC_E_NONE;
}
STATIC int32
_sys_at_eunit_set_run_status(uint8 lchip, uint8 eunit_id, uint32 run_status)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};

    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));

    cfg_cmd.done = 0;
    cfg_cmd.type = SYS_AT_EUNIT_CFG_RUN_STATUS;
    cfg_cmd.op   = SYS_EUNIT_CFG_OP_SET;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32*)&run_status, sizeof(uint32)/4));
    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_set_port_info(uint8 lchip, uint8 eunit_id, sys_eunit_config_port_info_t* p_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};

    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));

    cfg_cmd.done = 0;
    cfg_cmd.type = SYS_AT_EUNIT_PORT_INFO;
    cfg_cmd.op   = SYS_EUNIT_CFG_OP_SET;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32*)p_info, sizeof(sys_eunit_config_port_info_t)/4));
    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_set_port_mapping(uint8 lchip, uint8 eunit_id)
{
    uint8 gchip = 0;
    uint16 lport = 0;
    uint32 mac_id = 0;
    uint32 speed_mode = 0;
    sys_usw_dmps_port_info_t dmps_port_info = {0};
    sys_eunit_config_port_info_t port_info;

    sys_usw_get_gchip_id(lchip, &gchip);
    sal_memset(&port_info, 0, sizeof(sys_eunit_config_port_info_t));

    for(lport = 0; lport < MCHIP_CAP(SYS_CAP_PORT_NUM_PER_CHIP); lport++)
    {
        dmps_port_info.gport = CTC_MAP_LPORT_TO_GPORT(gchip, lport);
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_MAC_STATS_ID, (void *)&mac_id));
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_SPEED_MODE, (void *)&speed_mode));
        port_info.info[port_info.lport_num].mac_id = mac_id;
        port_info.info[port_info.lport_num].valid = 1;
        if (CTC_PORT_SPEED_800G == speed_mode)
        {
            port_info.info[port_info.lport_num].mac_num = 8;
        }
        else if (CTC_PORT_SPEED_400G == speed_mode)
        {
            port_info.info[port_info.lport_num].mac_num = 4;
        }
        else if (CTC_PORT_SPEED_200G == speed_mode)
        {
            port_info.info[port_info.lport_num].mac_num = 2;
        }
        else
        {
            port_info.info[port_info.lport_num].mac_num = 1;
        }
        port_info.lport_num++;
        if (port_info.lport_num >= 32)
        {
            CTC_ERROR_RETURN(_sys_at_eunit_set_port_info(lchip, eunit_id, &port_info));
            port_info.lport_num = 0;
        }
    }
    if (port_info.lport_num)
    {
        CTC_ERROR_RETURN(_sys_at_eunit_set_port_info(lchip, eunit_id, &port_info));
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_set_config(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    uint8 eunit_bmp = 0;
    uint8 eunit_id = 0;
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};

    CTC_ERROR_RETURN(_sys_at_eunit_map_cfg_unit(lchip, cfg_type, &eunit_bmp));

    do
    {
        if (!CTC_IS_BIT_SET(eunit_bmp, eunit_id))
        {
            continue;
        }

        CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
        /* Get CMD Memory */
        CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
        cfg_cmd.done = 0;
        cfg_cmd.op = SYS_EUNIT_CFG_OP_SET;
        switch (cfg_type)
        {
		case SYS_EUNIT_CFG_PTP_DOMAIN_0:
		case SYS_EUNIT_CFG_PTP_DOMAIN_1:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_PTP;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_ptp_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_LEARNING_AGING:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_LEARNING_AGING;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_learning_aging_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_LED:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_LED;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_peri_led_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_LED_MAPPING:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_LED_MAPPING;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_peri_led_mapping_t) / 4));
            break;
        case SYS_EUNIT_CFG_SENSOR_MONITOR:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_SENSOR_MONITOR;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_peri_sensor_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_HW_RESET:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_HW_RESET;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(uint32) / 4));
            break;
        case SYS_EUNIT_CFG_TOD:
            cfg_cmd.type = SYS_AT_EUNIT_TOD;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(uint32) * 32 / 4));/*TOD
 message length is uint8 * 128*/
            break;
        default:
            return CTC_E_INVALID_PARAM;
        }
        cfg_cmd.valid = 1;
        CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
        CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    } while (++eunit_id < MCHIP_CAP(SYS_CAP_EUNIT_NUM));
    return CTC_E_NONE;
}

int32
sys_at_eunit_mcpu_set_config(uint8 lchip, uint8 idx, uint32* value)
{
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    McpuMiscExtInfo0_m ext_info;

    tbl_id = McpuMiscExtInfo0_t + (McpuMiscExtInfo1_t - McpuMiscExtInfo0_t)*idx;
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &ext_info));
    SetMcpuMiscExtInfo0(V, miscExtInfo0_f, &ext_info, *value);
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &ext_info));

    return CTC_E_NONE;
}

int32
sys_at_eunit_mcpu_get_config(uint8 lchip, uint8 idx, uint32* value)
{
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    McpuMiscExtInfo0_m ext_info;

    tbl_id = McpuMiscExtInfo0_t + (McpuMiscExtInfo1_t - McpuMiscExtInfo0_t)*idx;
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, (M_UNTT_MAX_NUM - 1), cmd, &ext_info));
    *value = GetMcpuMiscExtInfo0(V, miscExtInfo0_f, &ext_info);

    return CTC_E_NONE;
}


STATIC int32
_sys_at_eunit_get_config(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    uint32 offset = 0;
    uint8 eunit_bmp = 0;
    uint8 eunit_id = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};

    CTC_ERROR_RETURN(_sys_at_eunit_map_cfg_unit(lchip, cfg_type, &eunit_bmp));

    do
    {
        if (!CTC_IS_BIT_SET(eunit_bmp, eunit_id))
        {
            continue;
        }

        CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
        /* Get CMD Memory */
        CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
        cfg_cmd.done = 0;
        cfg_cmd.op = SYS_EUNIT_CFG_OP_GET;
        /* config get operation codition */
        switch (cfg_type)
        {
        case SYS_EUNIT_CFG_PTP_DOMAIN_0:
        case SYS_EUNIT_CFG_PTP_DOMAIN_1:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_PTP;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_ptp_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_LEARNING_AGING:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_LEARNING_AGING;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_learning_aging_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_SENSOR_MONITOR:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_SENSOR_MONITOR;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_peri_sensor_cfg_t) / 4));
            break;         
        case SYS_EUNIT_CFG_TOD:
            cfg_cmd.type = SYS_AT_EUNIT_TOD;
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(uint32) * 32 / 4));/*TOD message length is uint8 * 128*/
            break;
        default:
            break;
        }
        cfg_cmd.valid = 1;
        CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
        CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
        switch (cfg_type)
        {
		case SYS_EUNIT_CFG_PTP_DOMAIN_0:
		case SYS_EUNIT_CFG_PTP_DOMAIN_1:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_PTP;
            CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_ptp_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_LEARNING_AGING:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_LEARNING_AGING;
            CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_learning_aging_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_SENSOR_MONITOR:
            cfg_cmd.type = SYS_AT_EUNIT_CFG_SENSOR_MONITOR;
            CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(sys_eunit_peri_sensor_cfg_t) / 4));
            break;
        case SYS_EUNIT_CFG_TOD:
            cfg_cmd.type = SYS_AT_EUNIT_TOD;
            CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_cfg, sizeof(uint32) * 32 / 4));/*TOD message length is uint8 * 128*/
            break;
        default:
            break;
        }
        break;
    } while (++eunit_id < MCHIP_CAP(SYS_CAP_EUNIT_NUM));
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_get_usr_config(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    uint32  offset = 0;
    uint8   eunit_id = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    ctc_eunit_cfg_t *p_usr_cfg = (ctc_eunit_cfg_t*)p_cfg;
    uint8 eunit_inner_used[] = {1,1,0,0,1,1,0,0};/*ecpu 0/1/4/5 is reserved for internal used*/
    uint8 eunit_cfg_type =0;
    uint8 is_working;

    CTC_PTR_VALID_CHECK(p_usr_cfg);
    CTC_PTR_VALID_CHECK(p_usr_cfg->p_data);
    CTC_MAX_VALUE_CHECK(p_usr_cfg->eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    if (CTC_EUNIT_CFG_TYPE_DEBUG == p_usr_cfg->type)
    {
        eunit_cfg_type = SYS_AT_EUNIT_CFG_DBG;
    }
    else
    {
        CTC_MIN_VALUE_CHECK(p_usr_cfg->type, CTC_EUNIT_CFG_TYPE_CUSTOM_BASE);
        if (eunit_inner_used[p_usr_cfg->eunit_id])
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is reserved, not allowed to get config\n", p_usr_cfg->eunit_id);
            return CTC_E_INVALID_CONFIG;
        }
        eunit_cfg_type = p_usr_cfg->type;
    }

    eunit_id = p_usr_cfg->eunit_id;
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is not working\n", eunit_id);
        return CTC_E_NOT_READY;
    }
    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
    
    cfg_cmd.done     = 0;
    cfg_cmd.op       = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.data_len = p_usr_cfg->data_len;
    cfg_cmd.type     = eunit_cfg_type;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_usr_cfg->p_data, cfg_cmd.data_len / 4));    
    
    cfg_cmd.valid = 1;
    
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));

    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_usr_cfg->p_data, cfg_cmd.data_len / 4));
    
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_set_usr_config(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    uint32  offset = 0;
    uint8   eunit_id = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    ctc_eunit_cfg_t *p_usr_cfg = (ctc_eunit_cfg_t*)p_cfg;
    uint8 eunit_inner_used[] = {1,1,0,0,1,1,0,0};/*ecpu 0/1/4/5 is reserved for internal used*/
    uint8 eunit_cfg_type =0;
    uint8 is_working;

    CTC_PTR_VALID_CHECK(p_usr_cfg);
    CTC_PTR_VALID_CHECK(p_usr_cfg->p_data);
    CTC_MAX_VALUE_CHECK(p_usr_cfg->eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    if (CTC_EUNIT_CFG_TYPE_DEBUG == p_usr_cfg->type)
    {
        eunit_cfg_type = SYS_AT_EUNIT_CFG_DBG;
    }
    else
    {
        CTC_MIN_VALUE_CHECK(p_usr_cfg->type, CTC_EUNIT_CFG_TYPE_CUSTOM_BASE);
        if (eunit_inner_used[p_usr_cfg->eunit_id])
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is reserved, not allowed to set config\n", p_usr_cfg->eunit_id);
            return CTC_E_INVALID_CONFIG;
        }
        eunit_cfg_type = p_usr_cfg->type;
    }

    eunit_id = p_usr_cfg->eunit_id;
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Eunit %d is not working\n", eunit_id);
        return CTC_E_NOT_READY;
    }
    /* temp code, build lport to mac_id mapping in Eunit for tsx mac stats*/
    CTC_ERROR_RETURN(_sys_at_eunit_set_port_mapping(lchip, eunit_id));
    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));

    cfg_cmd.done     = 0;
    cfg_cmd.op       = SYS_EUNIT_CFG_OP_SET;
    cfg_cmd.data_len = p_usr_cfg->data_len;
    cfg_cmd.type     = eunit_cfg_type;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_usr_cfg->p_data, cfg_cmd.data_len / 4));    
    
    cfg_cmd.valid = 1;
    
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    
    return CTC_E_NONE;  
}

STATIC int32
_sys_at_eunit_get_emic_ver(uint8 lchip, uint8 eunit_id, sys_eunit_emic_ver_t* p_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type    = SYS_AT_EUNIT_CFG_EMIC_VER;
    cfg_cmd.valid   = 1;
    cfg_cmd.eunit_id = eunit_id;
    
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_info, sizeof(sys_eunit_emic_ver_t) / 4));

    return CTC_E_NONE;
}

// STATIC int32
// _sys_at_eunit_show_cmd_info(uint8 lchip, uint8 eunit_id)
// {
//     uint32 offset = 0;
//     sys_eunit_cfg_cmd_t cfg_cmd = {0};
//     CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
//     /* Get CMD Memory */
//     CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
//     cfg_cmd.done    = 0;
//     cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
//     cfg_cmd.type    = SYS_AT_EUNIT_CFG_CMD_INFO;
//     cfg_cmd.valid   = 1;
//     cfg_cmd.eunit_id = eunit_id;
    
//     CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
//     CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
//     //CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_info, sizeof(sys_eunit_emic_ver_t) / 4));

//     return CTC_E_NONE;
// }

STATIC int32
_sys_at_eunit_get_mem_info(uint8 lchip, uint8 eunit_id, sys_eunit_mem_info_t *p_mem_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    
    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type    = SYS_AT_EUNIT_MEM_INFO;
    cfg_cmd.valid   = 1;
    cfg_cmd.eunit_id = eunit_id;
    
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_mem_info, sizeof(sys_eunit_mem_info_t) / 4));

    //SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"total:%d, used:%d, max_alloc:%d\n", mem_info.total, mem_info.ram_used, mem_info.ram_alloc_max);
    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_init(uint8 lchip)
{
    uint32 idx;
    uint16 shift = 0;
    uint32 cmd = 0;
    ds_t ds;
    uint32 rst_tbl_id[SYS_AT_EUNIT_NUM_PER_CORE] = {Ecpu00ResetCtl_t, Ecpu01ResetCtl_t, Ecpu10ResetCtl_t, Ecpu11ResetCtl_t};
    Ecpu00ResetCtl_m rst_ctl;
    uint8 eunit_id = 0;

    cmd = DRV_IOR(EcpuSupEnClk_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
    SetEcpuSupEnClk(V, enClkGlobalAxi_f, ds, 1);
    cmd = DRV_IOW(EcpuSupEnClk_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));

    sal_memset(ds, 0, sizeof(ds));
    shift = Ecpu01MemBase_t - Ecpu00MemBase_t;
    for (idx = 0; idx < 4; idx++)
    {
        cmd = DRV_IOW(Ecpu00MemBase_t + idx * shift, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
    }

    /* simulate RTL ECPU design��Ecpu00ResetCtl.cfgEcpuIntfReset/cfgEcpuCoreReset is always 1 before ECPU working */
    for (eunit_id = 0; eunit_id < SYS_AT_EUNIT_NUM_PER_CORE; eunit_id ++)
    {
        cmd = DRV_IOR(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &rst_ctl));
        SetEcpu00ResetCtl(V, cfgEcpuIntfReset_f, &rst_ctl, 1);
        SetEcpu00ResetCtl(V, cfgEcpuCoreReset_f, &rst_ctl, 1);
        cmd = DRV_IOW(rst_tbl_id[SYS_AT_EUNIT_ID_MASK(eunit_id)], DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &rst_ctl));
    }
    

    return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}

#define ______SYS_MCHIP_API______
int32
sys_at_eunit_isr_handler(uint8 lchip, uint32 intr, void* p_data)
{

    uint8 irq_id = 0;
    uint8 eunit_id = intr - SYS_INTR_CPU_SUB_ECPU_00 + ((lchip != SYS_PP_BASE(lchip))?SYS_AT_EUNIT_NUM_PER_CORE:0);
    uint32 cmd = 0;
    sys_intr_type_t type;
    uint32 intr_bmp[4] = {0};
    IntrIntCtl_m intr_ctl;

    cmd = DRV_IOR(IntrIntCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &intr_ctl));
    GetIntrIntCtl(A, intrIntCtl_f, &intr_ctl, intr_bmp);

    for (irq_id = 0; irq_id < 128; irq_id++)
    {
        if (!CTC_BMP_ISSET(intr_bmp, irq_id))
        {
            continue;
        }
        _sys_at_eunit_irq_dispatch(lchip, eunit_id, irq_id);
    }

    sal_memset(&type, 0, sizeof(sys_intr_type_t));
    type.intr = intr;
    sys_usw_interrupt_set_en(lchip, &type, FALSE);

    return CTC_E_NONE;
}


int32
sys_at_eunit_set_cfg(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    switch (cfg_type)
    {
        case SYS_EUNIT_CFG_TSX:
        case SYS_EUNIT_CFG_IFA:
        case SYS_EUNIT_CFG_TEX:
        case SYS_EUNIT_CFG_MOX:
	    case SYS_EUNIT_CFG_PTP_DOMAIN_0:
		case SYS_EUNIT_CFG_PTP_DOMAIN_1:
        case SYS_EUNIT_CFG_LEARNING_AGING:
        case SYS_EUNIT_CFG_LED:
        case SYS_EUNIT_CFG_LED_MAPPING:
        case SYS_EUNIT_CFG_SENSOR_MONITOR:
        case SYS_EUNIT_CFG_TOD:
            CTC_ERROR_RETURN(_sys_at_eunit_set_config(lchip, cfg_type, p_cfg));
            break;
        case SYS_EUNIT_CFG_USER_CFG:
            CTC_ERROR_RETURN(_sys_at_eunit_set_usr_config(lchip, cfg_type, p_cfg));
            break;
        case SYS_EUNIT_CFG_HW_RESET:
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }
    return CTC_E_NONE;
}

int32
sys_at_eunit_get_cfg(uint8 lchip, uint8 cfg_type, void* p_cfg)
{
    switch (cfg_type)
    {
        case SYS_EUNIT_CFG_TSX:
        case SYS_EUNIT_CFG_IFA:
        case SYS_EUNIT_CFG_TEX:
        case SYS_EUNIT_CFG_PTP_DOMAIN_0:
        case SYS_EUNIT_CFG_PTP_DOMAIN_1:
        case SYS_EUNIT_CFG_LEARNING_AGING:
        case SYS_EUNIT_CFG_SENSOR_MONITOR:
        case SYS_EUNIT_CFG_TOD:

            CTC_ERROR_RETURN(_sys_at_eunit_get_config(lchip, cfg_type, p_cfg));
            break;
        case SYS_EUNIT_CFG_APP_STATUS:
            CTC_ERROR_RETURN(_sys_at_eunit_get_app_status(lchip, cfg_type, p_cfg));
            break;
        case SYS_EUNIT_CFG_USER_CFG:
            CTC_ERROR_RETURN(_sys_at_eunit_get_usr_config(lchip, cfg_type, p_cfg));
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }
    return CTC_E_NONE;
}


int32
sys_at_eunit_get_unit_id(uint8 lchip, uint8 cfg_type, uint8* eunit)
{
    uint8 eunit_bmp = 0;
    uint8 i = 0;
    *eunit = 0xFF;
    CTC_ERROR_RETURN(_sys_at_eunit_map_cfg_unit(lchip, cfg_type, &eunit_bmp));
    do
    {
        if (CTC_IS_BIT_SET(eunit_bmp, i))
        {
            *eunit = i;
            return CTC_E_NONE;
        }
    }while(++i < MCHIP_CAP(SYS_CAP_EUNIT_NUM));
    return CTC_E_NOT_EXIST;
}

int32
sys_at_eunit_get_pclog(uint8 lchip, uint8 eunit_id, uint64* pc_arr, uint8* num)
{
    uint32 cmd = 0;
    uint32 tbl_id = (Ecpu01DebugPcLog_t - Ecpu00DebugPcLog_t) * SYS_AT_EUNIT_ID_MASK(eunit_id) + Ecpu00DebugPcLog_t;
    Ecpu00DebugPcLog_m ecpu_pclog;
    uint32 data[4];
    uint64 pc[3];
    uint8 idx;

    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_PP_EN(cmd), &ecpu_pclog));
    GetEcpu01DebugPcLog(A, debugPcLog_f, &ecpu_pclog, data);

    /* 40bits per pc pointer
     *        bit31                                       bit0
     *         +----------+----------+----------+----------+
     * data 0: |                 pc0[31:0]                 |
     *         +----------+----------+----------+          +
     * data 1: |          pc1[23:0]             |pc0[39:32]|
     *         +----------+----------+          +----------+
     * data 2: |       pc2[15:0]     |       pc1[39:24]    |
     *         +----------+          +----------+----------+
     * data 3:            |            pc2[39:16]          |
     *                    +----------+----------+----------+s
     */
    pc[0] = data[1] & 0xff;
    pc[0] <<= 32;
    pc[0] |= data[0];

    pc[1] = data[2] & 0xffff;
    pc[1] <<= 24;
    pc[1] |= (data[1] >> 8);

    pc[2] = data[3] & 0xffffff;
    pc[2] <<= 16;
    pc[2] |= (data[2] >> 16);

    for (idx = 0; idx < (*num < 3?*num:3); idx++)
    {
        pc_arr[idx] = pc[idx];
    }
    *num = 3;

    return CTC_E_NONE;
}



int32
sys_at_eunit_show_debug_info(uint8 lchip, uint8 eunit_id)
{
    uint32 offset = 0;
    int32 ret = CTC_E_NONE;
    sys_usw_eunit_dbg_hdr_t dbg_hdr = {0};
    char* p_buf;
    char* p_str;
    uint32 idx = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_DBG_BUF_ADDR, &offset));
    if (!offset)
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset); /*convert to pcie addr*/
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset, (uint32*)&dbg_hdr, sizeof(sys_usw_eunit_dbg_hdr_t)/4));
    if (!dbg_hdr.size)
    {
        return CTC_E_NONE;
    }
    p_buf = mem_malloc(MEM_SYSTEM_MODULE, dbg_hdr.size*dbg_hdr.line);
    if (NULL == p_buf)
    {
        return CTC_E_NO_MEMORY;
    }
    ret = _sys_at_eunit_read_mem(lchip, offset + sizeof(sys_usw_eunit_dbg_hdr_t), (uint32*)p_buf, (dbg_hdr.size*dbg_hdr.line)/4);
    if (ret < 0)
    {
        goto error_back;
    }
    do
    {
        p_str = p_buf + idx * dbg_hdr.size;
        if (!sal_strlen(p_str))
        {
            continue;
        }
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", p_str);
    }while(++idx < dbg_hdr.line);

error_back:
    mem_free(p_buf);
    return ret;
}

#include "sys_at_eunit0.inc"
#include "sys_at_eunit1.inc"
#include "sys_at_eunit4.inc"

int32
sys_at_eunit_reset(uint8 lchip, uint8 eunit_id, ctc_eunit_install_t* p_eunit)
{
    uint8 is_working = 0; 
    uint8 is_reset = 0;
    uint32 boot_addr = 0;
    uint32 value = 0;
    sys_at_eunit_boot_info_t boot_info = {0};

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);


    CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, eunit_id, &is_reset));
    if(!is_reset)
    {
        CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
        CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &value));
    }
    
    if (p_eunit)
    {
        /*install*/
        if (is_working || (!is_working && value && !is_reset))
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "need uninstall eunit firstly! eunit_id:%u\n", eunit_id);
            return CTC_E_IN_USE;
        }
        if (p_eunit->bin_file)
        {
            CTC_ERROR_RETURN(_sys_at_eunit_get_boot_info(lchip, eunit_id, p_eunit, &boot_info));
            boot_addr = boot_info.boot_addr;
        }
        else
        {
            boot_addr = _sys_at_eunit_get_fixed_boot_addr(lchip, eunit_id);
            boot_info.boot_addr = boot_addr;
            boot_info.size      = _sys_at_eunit_get_fixed_boot_size(lchip, eunit_id);
        }
        
        if (p_eunit->bin_file)
        {
            CTC_ERROR_RETURN(_sys_at_eunit_load_file(lchip, boot_addr, p_eunit->bin_file));
        }
        else if (p_eunit->bin_data && p_eunit->bin_size)
        {
            CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, boot_addr, p_eunit->bin_data, p_eunit->bin_size / sizeof(uint32)));
        }
        else
        {
            /*default: eunit0 store CPU-LED, sensor monitor */
            if (eunit_id == 0)
            {
                CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, boot_addr, g_at_eunit0_bin, sizeof(g_at_eunit0_bin) / sizeof(uint32)));
            }
            /*default: eunit1 store ptp domain 0 */
            else if (eunit_id == 1)
            {
                CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, boot_addr, g_at_eunit1_bin,sizeof(g_at_eunit1_bin) / sizeof(uint32)));
            }
            /*default: eunit4 store learning-aging */
            else if (eunit_id == 4)
            {
                CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, boot_addr, g_at_eunit4_bin,sizeof(g_at_eunit4_bin) / sizeof(uint32)));
            }
            
        }
        CTC_ERROR_RETURN(_sys_at_eunit_release_reset(lchip, eunit_id, boot_addr, 1));
        CTC_ERROR_RETURN(_sys_at_eunit_set_boot_info(lchip, eunit_id));

        sal_task_sleep(1000);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"eunit_id:%d, boot_addr:0x%x, size:%d\n", eunit_id, boot_info.boot_addr, boot_info.size);
        
        CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
        if (!is_working)
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "eunit[%u] is not working!\n", eunit_id);
        }
        CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_write(lchip, eunit_id,
                                                          SYS_AT_EUNIT_MISC_EXT_MEM_SIZE,
                                                          boot_info.size));
    }
    else
    {
        if (!is_working)
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "eunit is not worked. donot need uninstall! eunit_id:%u\n", eunit_id);
        }

        /*reset ecpu*/
        CTC_ERROR_RETURN(_sys_at_eunit_release_reset(lchip, eunit_id, 0, 0));
    }

    return CTC_E_NONE;
}



int32
sys_at_eunit_read_data(uint8 lchip, uint8 cfg_type, void* p_data,uint16 lenth)
{
    uint8 eunit_bmp = 0;
    uint8 eunit_id = 0;
    uint32 offset = 0;
	uint8 type = 0;

	CTC_ERROR_RETURN(_sys_at_eunit_map_misc_int_type(lchip,cfg_type,&type));
    CTC_ERROR_RETURN(_sys_at_eunit_map_cfg_unit(lchip, cfg_type, &eunit_bmp));

    do
    {
        if (!CTC_IS_BIT_SET(eunit_bmp, eunit_id))
        {
            continue;
        }
		CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, type, &offset));
		SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset);
		CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset, (uint32 *)p_data, lenth / 4));
    } while (++eunit_id < MCHIP_CAP(SYS_CAP_EUNIT_NUM));

	return CTC_E_NONE;
}

STATIC int32
_sys_at_eunit_dump_thread_info(uint8 lchip, uint8 eunit_id)
{
    uint32 offset = 0;
    uint8 index = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    sys_usw_eunit_thread_info_list_t info_list;
    char* str_stat[] = {"init", "ready", "suspend", "runing", "close"};

    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));

    cfg_cmd.done    = 0;
    cfg_cmd.type    = SYS_AT_EUNIT_DUMP_THREAD_INFO;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.valid   = 1;
    
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32*)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t)/4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32*)&info_list, sizeof(sys_usw_eunit_thread_info_list_t)/4));
    if (!info_list.info_num)
    {
        return CTC_E_NONE;
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\nindex(%-u) %-20s  %-10s  %-10s %-10s %-8s %-4s\n", info_list.info_num, "ThreadName", "Func", "Stack", "StackSize", "Stat", "Prio");

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------------------------------------------\n");
    for (index = 0; index < info_list.info_num; index++)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-8u %-20s  0x%08x  0x%08x %-10u %-8s %-4u\n", index, info_list.info[index].name,
                                                                                       info_list.info[index].sp,
                                                                                       info_list.info[index].stack_addr,
                                                                                       info_list.info[index].stack_size,
                                                                                       str_stat[info_list.info[index].stat > 4 ? 0 : info_list.info[index].stat],
                                                                                       info_list.info[index].priority);

    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------------------------------------------\n");
    return CTC_E_NONE;
}

int32
_sys_at_eunit_show_status_by_eunit_id(uint8 lchip, uint8 eunit_id)
{
    int32 ret = 0;
    uint8 is_working = 0;
    uint32 offset = 0;
    uint32 name_offset = 0;
    uint32 value = 0;
    uint8 is_reset = 0;
    sys_usw_eunit_app_info_hdr_t app_name_hdr;
    uint8 app_id = 0, app_num=0;
    sys_usw_eunit_app_info_body_t app_info;
    sys_eunit_mem_info_t mem_info={0};

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, eunit_id, &is_reset));
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:%u\n", eunit_id);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");
    if (!is_working)
    {
        value = 0;
        if (!is_reset)
        {
            CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &value));
        }
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", value ? "Not Worked (crashed)\n" : "Not Worked (uninstall)\n");
        return CTC_E_NONE;
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", "Working");
    CTC_ERROR_RETURN(_sys_at_eunit_get_boot_addr(lchip, eunit_id, &value));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: 0x%.8x\n", "Boot Pcie Addr", SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, value));
    CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &value));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u kB\n", "Memory Size", value);
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_CMD_MEM_ADDR, &value));

    CTC_ERROR_RETURN(_sys_at_eunit_get_mem_info(lchip, eunit_id, &mem_info));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u B\n", "Total Heap Size", mem_info.total);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u B\n", "Used  Heap Size", mem_info.ram_used);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u B\n", "Max Heap Used Size", mem_info.ram_used_max);

    
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: 0x%x\n", "Config Pcie Addr", SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, value));
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_DBG_BUF_ADDR, &value));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: 0x%x\n", "Debug Pcie Addr", SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, value));
    
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_ALIVE_CNT, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset), &value, 1));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u\n", "Chip Alive Count", value);
    
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_FEATURES_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset), (uint32*)&app_name_hdr, 1));
    app_num = app_name_hdr.app_num;

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %u\n", "App Num", app_num);
    
    for(app_id = 0; app_id<app_num; app_id++)
    {
        name_offset = (SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset) + 4) + app_id*sizeof(sys_usw_eunit_app_info_body_t);
        
        memset(&app_info, 0, sizeof(app_info));
        
        CTC_ERROR_GOTO(_sys_at_eunit_read_mem(lchip, name_offset, (uint32*)&app_info, sizeof(sys_usw_eunit_app_info_body_t)/4), ret, error_back);
        if(!sal_strlen(app_info.app_name))
        {
            continue;
        }
        
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s(%d)\n", "Working Feature", app_info.app_name, app_info.app_id);
    }
    CTC_ERROR_RETURN(_sys_at_eunit_dump_thread_info(lchip, eunit_id));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
        
    return CTC_E_NONE;

error_back:
    return ret;
}

int32
_sys_at_eunit_show_status_by_all(uint8 lchip)
{
    uint8 eunit_id;   
    uint8 is_working = 0;
    uint8 is_reset = 0;
    uint32 value = 0;

    for (eunit_id = SYS_AT_EUNIT_ID_0; eunit_id < MCHIP_CAP(SYS_CAP_EUNIT_NUM); eunit_id++)
    {
        CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, eunit_id, &is_reset));
        CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:%u\n", eunit_id);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");
        if (!is_working)
        {
            value = 0;
            if (!is_reset)
            {
                CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &value));
            }
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", value ? "Not Worked (crashed)\n" : "Not Worked (uninstall)\n");
        }
        else
        {
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", "Working\n");
        }
    }
    return CTC_E_NONE;
}


int32
_sys_at_eunit_show_status_by_app_id(uint8 lchip, uint8 eunit_id, uint8 app_id)
{
    int32 ret = CTC_E_NONE;
    uint8 is_working = 0;
    uint32 offset = 0;
    uint32 info_offset = 0;
    char* p_str = NULL;
    uint32 value = 0;
    uint8 is_reset = 0;
    sys_usw_eunit_app_info_hdr_t app_name_hdr;
    uint8 app_num=0;
    sys_usw_eunit_app_info_body_t app_info;
    uint8 idx = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, eunit_id, &is_reset));
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "EUNIT_ID:%u\n", eunit_id);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------------\n");
    if (!is_working)
    {
        value = 0;
        if (!is_reset)
        {
            CTC_ERROR_RETURN(_sys_at_eunit_misc_ext_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_EXT_MEM_SIZE, &value));
        }
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s\n", "Working Status", value ? "Not Worked (crashed)\n" : "Not Worked (uninstall)\n");
        return CTC_E_NONE;
    }
    
    CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, eunit_id, SYS_AT_EUNIT_MISC_INT_FEATURES_ADDR, &offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset), (uint32*)&app_name_hdr, 1));
    app_num = app_name_hdr.app_num;

    for(idx = 0; idx<app_num; idx++)
    {
        info_offset = (SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, offset) + 4) + idx*sizeof(sys_usw_eunit_app_info_body_t);

        memset(&app_info, 0, sizeof(app_info));
        
        CTC_ERROR_GOTO(_sys_at_eunit_read_mem(lchip, info_offset, (uint32*)&app_info, sizeof(sys_usw_eunit_app_info_body_t)/4), ret, error_back);

        if(app_info.app_id == app_id)
        {
            break;
        }
    }

    if(idx == app_num)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "invalid app:%d\n", app_id);
        return CTC_E_INVALID_PARAM;
    }

    p_str = app_info.app_name;
    
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s: %s(%d)\n", "Working Feature", p_str, app_id);

    if (NULL != sal_strstr(p_str, EUNIT_FEATURE_STR_REMOTE_CFG))
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "detail info:\n");
    }
    if (NULL != sal_strstr(p_str, EUNIT_FEATURE_STR_LEARNING_AGING))
    {
        sys_eunit_learning_aging_cfg_t la_cfg;
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "detail info:\n");
        sal_memset(&la_cfg, 0, sizeof(sys_eunit_learning_aging_cfg_t));
        CTC_ERROR_GOTO(_sys_at_eunit_get_config(lchip, SYS_EUNIT_CFG_LEARNING_AGING, &la_cfg), ret, error_back);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    %-20s: %u\n",     ".hw_learn", la_cfg.enable);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    %-20s: %u\n",     ".aging_cnt", la_cfg.aging_cnt);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    %-20s: %u\n",     ".learn_cnt", la_cfg.learn_cnt);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    %-20s: %u\n",     ".conflict-sync", la_cfg.conflict_sync_en);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    %-20s: 0x%x\n",   ".conflict-sync-buf", la_cfg.conflict_fifo_depth);
    }
    if (NULL != sal_strstr(p_str, EUNIT_FEATURE_STR_SENSOR_MONITOR))
    {
        sys_eunit_peri_sensor_cfg_t sen_cfg;
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    active sensor-list:\n");
        CTC_ERROR_GOTO(_sys_at_eunit_get_config(lchip, SYS_EUNIT_CFG_SENSOR_MONITOR, &sen_cfg), ret, error_back);
        for (value = 0; value < CTC_MAX_CHIP_SENSOR; value++)
        {
            if (CTC_IS_BIT_SET(sen_cfg.sensor_bmp, value) && sen_cfg.interval)
            {
                SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "         %s%u\n", "sensor", value);
            }
        }
    }
        
    return CTC_E_NONE;

error_back:
    return ret;    
}

int32
sys_at_eunit_show_status(uint8 lchip, uint8 level, void* p_params)
{
    uint8 eunit_id = 0;
    uint8 app_id = 0;
    sys_usw_eunit_status_params_t *params;

    params = (sys_usw_eunit_status_params_t*)p_params;
    switch(level)
    {
        case 0:
            CTC_ERROR_RETURN(_sys_at_eunit_show_status_by_all(lchip));
            break;
        
        case 1:
            CTC_PTR_VALID_CHECK(p_params);
            eunit_id = params->eunit_id;
            CTC_ERROR_RETURN(_sys_at_eunit_show_status_by_eunit_id(lchip, eunit_id));
            break;
            
        case 2:
            CTC_PTR_VALID_CHECK(p_params);
            eunit_id = params->eunit_id;
            app_id = params->app_id;
            CTC_ERROR_RETURN(_sys_at_eunit_show_status_by_app_id(lchip, eunit_id, app_id));
            break;
            
        default:
            return CTC_E_INVALID_PARAM;            
    }

    return CTC_E_NONE;
}

int32
_sys_at_eunit_get_dma_info(uint8 lchip, uint8 eunit_id, sys_eunit_dma_info_t* p_info)
{
    uint32 offset = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type    = SYS_AT_EUNIT_DMA_INFO;
    cfg_cmd.valid   = 1;
    cfg_cmd.eunit_id = eunit_id;
    
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_info, sizeof(sys_eunit_dma_info_t) / 4));

    return CTC_E_NONE;
}

int32
sys_at_eunit_show_dma_stats(uint8 lchip, uint8 eunit_id)
{
    /*
     even index is good stats;
     odd index is bad stats;
    */
    DmaPktRxStats_m rx_stats;
    DmaPktTxStats_m tx_stats;
    uint16 idx = 0;
    uint8 ring = 0;
    uint32 cmd = 0;
    uint64 bytes = 0;
    uint64 count = 0;
    sys_eunit_dma_info_t dma_info;
    uint8 is_working = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }
    sal_memset(&dma_info, 0, sizeof(sys_eunit_dma_info_t));
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    _sys_at_eunit_get_dma_info(lchip, eunit_id, &dma_info);
    SYS_AT_EUNIT_DMA_RESET_CHECK(lchip, dma_info.dma_sel);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ECPUDMA%d Receive Stats:\n", dma_info.dma_sel);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6s%-21s%-21s%-21s%-21s\n", "Ring", "GoodPktCnt", "GoodPktByte", "BadPktCnt", "BadPktByte");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");

    for (ring = 0; ring < SYS_AT_PER_DMA_CTL_RX_RING_NUM; ring++)
    {
        if (!CTC_IS_BIT_SET(dma_info.ring_bmp, ring))
        {
            continue;
        }
        idx = (dma_info.dma_sel ? 32 : 16) + ring * 2;
        cmd = DRV_IOR(DmaPktRxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, DRV_CMD_PP_EN(cmd), &rx_stats));
        count = GetDmaPktRxStats(V, frameCntHi_f, &rx_stats);
        count <<= 32;
        count |= GetDmaPktRxStats(V, frameCntLo_f, &rx_stats);
        bytes = GetDmaPktRxStats(V, byteCntHi_f, &rx_stats);
        bytes <<= 32;
        bytes |= GetDmaPktRxStats(V, byteCntLo_f, &rx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-21"PRIu64"%-21"PRIu64, ring, count, bytes);

        cmd = DRV_IOR(DmaPktRxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx + 1, DRV_CMD_PP_EN(cmd), &rx_stats));
        count = GetDmaPktRxStats(V, frameCntHi_f, &rx_stats);
        count <<= 32;
        count |= GetDmaPktRxStats(V, frameCntLo_f, &rx_stats);
        bytes = GetDmaPktRxStats(V, byteCntHi_f, &rx_stats);
        bytes <<= 32;
        bytes |= GetDmaPktRxStats(V, byteCntLo_f, &rx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21"PRIu64"%-21"PRIu64"\n", count, bytes);
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ECPUDMA%d Transmit Stats:\n", dma_info.dma_sel);
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6s%-21s%-21s%-21s%-21s\n", "Ring", "GoodPktCnt", "GoodPktByte", "BadPktCnt", "BadPktByte");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------------------------\n");

    for (ring = SYS_AT_PER_DMA_CTL_RX_RING_NUM; ring < (SYS_AT_PER_DMA_CTL_RX_RING_NUM + SYS_AT_PER_DMA_CTL_TX_RING_NUM); ring++)
    {
        if (!CTC_IS_BIT_SET(dma_info.ring_bmp, ring))
        {
            continue;
        }
        idx = (dma_info.dma_sel ? 16 : 8) + (ring - SYS_AT_PER_DMA_CTL_RX_RING_NUM) * 2;
        cmd = DRV_IOR(DmaPktTxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, DRV_CMD_PP_EN(cmd), &tx_stats));
        count = GetDmaPktTxStats(V, frameCntHi_f, &tx_stats);
        count <<= 32;
        count |= GetDmaPktTxStats(V, frameCntLo_f, &tx_stats);
        bytes = GetDmaPktTxStats(V, byteCntHi_f, &tx_stats);
        bytes <<= 32;
        bytes |= GetDmaPktTxStats(V, byteCntLo_f, &tx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-21"PRIu64"%-21"PRIu64, ring, count, bytes);

        cmd = DRV_IOR(DmaPktTxStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx + 1, DRV_CMD_PP_EN(cmd), &tx_stats));
        count = GetDmaPktTxStats(V, frameCntHi_f, &tx_stats);
        count <<= 32;
        count |= GetDmaPktTxStats(V, frameCntLo_f, &tx_stats);
        bytes = GetDmaPktTxStats(V, byteCntHi_f, &tx_stats);
        bytes <<= 32;
        bytes |= GetDmaPktTxStats(V, byteCntLo_f, &tx_stats);
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-21"PRIu64"%-21"PRIu64"\n", count, bytes);
    }

    return CTC_E_NONE;
}

int32
sys_at_eunit_clear_dma_stats(uint8 lchip, uint8 eunit_id)
{
    /*
     even index is good stats;
     odd index is bad stats;
    */
    DmaPktRxStats_m rx_stats;
    DmaPktTxStats_m tx_stats;
    uint16 idx = 0;
	uint16 tbl_base = 0;
    uint32 cmd = 0;
    sys_eunit_dma_info_t dma_info;
    uint8 is_working = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }
    sal_memset(&dma_info, 0, sizeof(sys_eunit_dma_info_t));
    sal_memset(&rx_stats, 0, sizeof(DmaPktRxStats_m));
    sal_memset(&tx_stats, 0, sizeof(DmaPktTxStats_m));
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    _sys_at_eunit_get_dma_info(lchip, eunit_id, &dma_info);
    SYS_AT_EUNIT_DMA_RESET_CHECK(lchip, dma_info.dma_sel);

	/* clear rx stats */
	tbl_base = dma_info.dma_sel ? 32 : 16;
	cmd = DRV_IOW(DmaPktRxStats_t, DRV_ENTRY_FLAG);
    for (idx = tbl_base; idx < tbl_base+SYS_AT_PER_DMA_CTL_RX_RING_NUM*2; idx++)
    {
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, DRV_CMD_PP_EN(cmd), &rx_stats));
    }

	/* clear tx stats */
	tbl_base = dma_info.dma_sel ? 16 : 8;
	cmd = DRV_IOW(DmaPktTxStats_t, DRV_ENTRY_FLAG);
    for (idx = tbl_base; idx < tbl_base+SYS_AT_PER_DMA_CTL_TX_RING_NUM*2; idx++)
    {
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, DRV_CMD_PP_EN(cmd), &tx_stats));
    }

    return CTC_E_NONE;
}

int32
sys_at_eunit_set_run_status(uint8 lchip, uint8 eunit_id, uint32 run_status)
{
    uint8 is_working = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "eunit[%u] is not working!\n", eunit_id);
        return CTC_E_HW_FAIL;
    }
    if (SYS_EUNIT_RUN_STATUS_RUNNING != run_status && SYS_EUNIT_RUN_STATUS_SUSPEND != run_status )
    {
        return CTC_E_INVALID_PARAM;
    }
    CTC_ERROR_RETURN(_sys_at_eunit_set_run_status(lchip, eunit_id, run_status));
    return CTC_E_NONE;
}

int32
sys_at_eunit_show_version(uint8 lchip, uint8 eunit_id)
{
    uint8 is_working = 0;
    sys_eunit_emic_ver_t ver;

    sal_memset(&ver, 0, sizeof(ver));

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "eunit[%u] is not working!\n", eunit_id);
        return CTC_E_NOT_READY;
    }

    CTC_ERROR_RETURN(_sys_at_eunit_get_emic_ver(lchip, eunit_id, &ver));

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, 
    "    Eunit %d, EMIC Version %s, Date:%s.\n",
    eunit_id, ver.version, ver.date);
        
    return CTC_E_NONE;
}

int32
sys_at_eunit_init_deinit(uint8 lchip, uint8 is_deinit)
{
    if (is_deinit)
    {
        return _sys_at_eunit_deinit(lchip);
    }
    return _sys_at_eunit_init(lchip);
}

/* there are 2 bits per lock
 * +----------+-------------+---------------+
 * | lock_id  |  bit used   |   register    |
 * +----------+-------------+---------------+
 * |    0     | bit0,bit1   | Grant0ExtCtl  |
 * +----------+-------------+---------------+
 * |    1     | bit0,bit1   | Grant1ExtCtl  |
 * +----------+-------------+---------------+
 * |    2     | bit0,bit1   | Grant2ExtCtl  |
 * +----------+-------------+---------------+
 * |    3     | bit0,bit1   | Grant3ExtCtl  |
 * +----------+-------------+---------------+
 * |    4     | bit0,bit1   | Grant4ExtCtl  |
 * +----------+-------------+---------------+
 * |    5     | bit0,bit1   | Grant5ExtCtl  |
 * +----------+-------------+---------------+
 * |    6     | bit0,bit1   | Grant6ExtCtl  |
 * +----------+-------------+---------------+
 * |    7     | bit0,bit1   | Grant7ExtCtl  |
 * +----------+-------------+---------------+
 */
int32
sys_at_eunit_hw_lock(uint8 lchip, uint8 eunit_id, uint8 lock_id)
{
    Grant0ExtCtl_m extCtlw, extCtlr;
    uint64 cmdw = 0, cmdr = 0;
    uint32 timeout = 1000;
    uint32 value = 0;
    uint8 tmp_eunit_id = SYS_AT_EUNIT_ID_MASK(eunit_id);

    CTC_MAX_VALUE_CHECK(lock_id, SYS_AT_EUNIT_MAX_HW_LOCK_ID);
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    sal_memset(&extCtlw, 0, sizeof(extCtlw));
    SetGrant0ExtCtl(V, grant0ExtCtl_f, &extCtlw, 0x3);
    cmdw = DRV_IOW(Grant0ExtCtl_t + (Grant1ExtCtl_t - Grant0ExtCtl_t) * lock_id, DRV_ENTRY_FLAG);
    cmdw = DRV_CMD_PP_EN(cmdw);
    cmdr = DRV_IOR(Grant0ExtCtl_t + (Grant1ExtCtl_t - Grant0ExtCtl_t) * lock_id, DRV_ENTRY_FLAG);
    cmdr = DRV_CMD_PP_EN(cmdr);

    do {
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, tmp_eunit_id, cmdw, &extCtlw));
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, tmp_eunit_id, cmdr, &extCtlr));
        value = GetGrant0ExtCtl(V, grant0ExtCtl_f, &extCtlr);
        if(value & 0x1)
        {
            break;
        }
        sal_task_sleep(1);
    }while(--timeout);

    if (!timeout)
    {
        return CTC_E_MUTEX_BUSY;
    }

    return CTC_E_NONE;
}

int32
sys_at_eunit_hw_unlock(uint8 lchip, uint8 eunit_id, uint8 lock_id)
{
    Grant0ExtCtl_m extCtl;
    uint32 cmd;

    CTC_MAX_VALUE_CHECK(lock_id, SYS_AT_EUNIT_MAX_HW_LOCK_ID);
    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    sal_memset(&extCtl, 0, sizeof(extCtl));
    SetGrant0ExtCtl(V, grant0ExtCtl_f, &extCtl, 0);
    cmd = DRV_IOW(Grant0ExtCtl_t + (Grant1ExtCtl_t - Grant0ExtCtl_t) * lock_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_AT_EUNIT_ID_MASK(eunit_id), DRV_CMD_PP_EN(cmd), &extCtl));

    return CTC_E_NONE;
}

int32
sys_at_eunit_get_hw_lock(uint8 lchip, uint8 type, uint8* p_eunit_id, uint8* p_lock_id)
{
    uint32 value = 0;
    uint32 features = 0;
    uint8 e_id = 0;
    uint8 is_reset = 0;
    switch (type)
    {
    case SYS_EUNIT_CFG_LEARNING_AGING:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_LEARNING_AGING);
        *p_lock_id = SYS_EUNIT_LOCK_ID_FIBACC;
        break;
    case SYS_EUNIT_CFG_SENSOR_MONITOR:
        CTC_BIT_SET(features, SYS_AT_EUNIT_FEATURE_SENSOR_MONITOR);
        *p_lock_id = SYS_EUNIT_LOCK_ID_SENSOR;
        break;
    default:
        return CTC_E_INVALID_PARAM;
    }
    for (e_id = 0; e_id < MCHIP_CAP(SYS_CAP_EUNIT_NUM); e_id++)
    {
        CTC_ERROR_RETURN(_sys_at_eunit_is_reset(lchip, e_id, &is_reset));
        if (is_reset)
        {
            continue;
        }
        CTC_ERROR_RETURN(_sys_at_eunit_misc_int_ctl_read(lchip, e_id, SYS_AT_EUNIT_MISC_INT_FEATURES, &value));
        if (value & features)
        {
            *p_eunit_id = e_id;
        }
    }
    return CTC_E_NONE;

}

int32
sys_at_eunit_tbl_rw(uint8 lchip, uint8 eunit_id, void* p_data, uint8 op_type)
{
	uint32 offset = 0;
    uint8 is_working;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
	sys_usw_eunit_tbl_rw_t* p_tbl = (sys_usw_eunit_tbl_rw_t*)p_data;

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }

    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
    cfg_cmd.done    = 0;
    cfg_cmd.op      = (SYS_USW_EUNIT_TBL_RW_TYPE_READ == op_type) ? SYS_EUNIT_CFG_OP_GET : SYS_EUNIT_CFG_OP_SET;
    cfg_cmd.type    = SYS_AT_EUNIT_TBL_RW;
    cfg_cmd.valid   = 1;
    p_tbl->with_mask = (SYS_USW_EUNIT_TBL_RW_TYPE_WITH_MASK == op_type) ? 1:0;

    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_tbl, sizeof(sys_usw_eunit_tbl_rw_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), (uint32 *)p_tbl, sizeof(sys_usw_eunit_tbl_rw_t) / 4));

    return CTC_E_NONE;
}

int32
sys_at_eunit_show_dma_status(uint8 lchip, uint8 eunit_id)
{
    uint32 cmd = 0;
    uint32 tbl_base = 0;
    uint16 index = 0;
    uint32 ring_bmp = 0;
    uint32 vld_num = 0;
    uint32 ring_depth = 0;
    uint32 mem_base = 0;
    uint32 data_base = 0;
    DmaStaticInfo_m dma_info;
    DmaCtlTab_m ctl_tab;
    DsDesc_m ds_desc;
    sys_eunit_dma_info_t dma_use_info;
    char *dma_ring_func[SYS_AT_EUNIT_RING_NUM_PER_DMA_CTL] = {"PktRx0","PktRx1","PktRx2","PktRx3","PktRx4","PktRx5","PktRx6","PktRx7",\
                                                              "PktTx0","PktTx1","PktTx2","PktTx3",\
                                                              "TblRd0","TblRd1","TblRd2","TblRd3","TblRd4","TblRd5",\
                                                              "TblWr0","TblWr1",\
                                                              "Info0","Info1","Info2","Info3","Info4","Info5","Info6","Info7",\
                                                              "TcamScan","DmaBatch"};
    uint8 is_working = 0;

	CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);

    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }

    _sys_at_eunit_get_dma_info(lchip, eunit_id, &dma_use_info);
    SYS_AT_EUNIT_DMA_RESET_CHECK(lchip, dma_use_info.dma_sel);
    ring_bmp = dma_use_info.ring_bmp;

    if(SYS_AT_EUNIT_DMA0 == dma_use_info.dma_sel)
    {
        tbl_base = SYS_AT_EUNIT_DMA0_TBL_BASE;
    }
    else if (SYS_AT_EUNIT_DMA1 == dma_use_info.dma_sel)
    {
        tbl_base = SYS_AT_EUNIT_DMA1_TBL_BASE;
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6s%-10s%-10s%-7s%-7s%-15s  %-15s\n","Chan", "Function", "ValidNum","CurIdx", "Depth", "DescBase", "DataBase");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------------\n");
    for (index = 0; index < SYS_AT_EUNIT_RING_NUM_PER_DMA_CTL; index++)
    {
        cmd = DRV_IOR(DmaStaticInfo_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index+tbl_base, DRV_CMD_PP_EN(cmd), &dma_info));
        if (CTC_IS_BIT_SET(ring_bmp, index))
        {
            cmd = DRV_IOR(DmaCtlTab_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, index+tbl_base, DRV_CMD_PP_EN(cmd), &ctl_tab));
            vld_num = GetDmaCtlTab(V, vldNum_f, &ctl_tab);
            ring_depth = GetDmaStaticInfo(V, ringDepth_f, &dma_info);
            mem_base = GetDmaStaticInfo(V, ringBase_f, &dma_info);
            mem_base <<= 4;
            if (eunit_id >= SYS_AT_EUNIT_NUM_PER_CORE)
            {
                mem_base |= SYS_AT_EUNIT_REMOTE_BASE;
            }
            CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, mem_base), (uint32*)&ds_desc, sizeof(DsDesc_m)/sizeof(uint32)));
            data_base = GetDsDesc(V, memAddr_f, &ds_desc) << 4;
            if (eunit_id >= SYS_AT_EUNIT_NUM_PER_CORE)
            {
                data_base |= SYS_AT_EUNIT_REMOTE_BASE;
            }
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-6u%-10s%-10u%-7u%-7u0x%-13x  0x%-13x\n",
                index, dma_ring_func[index], vld_num, dma_use_info.desc_cur_idx[index], ring_depth, mem_base, data_base);
        }
    }
    if (0 == dma_use_info.ring_bmp_cross_core)
    {
        return CTC_E_NONE;
    }
    ring_bmp = dma_use_info.ring_bmp_cross_core;
    if(SYS_AT_EUNIT_DMA0 == dma_use_info.dma_sel_cross_core)
    {
        tbl_base = SYS_AT_EUNIT_DMA0_TBL_BASE;
    }
    else if (SYS_AT_EUNIT_DMA1 == dma_use_info.dma_sel_cross_core)
    {
        tbl_base = SYS_AT_EUNIT_DMA1_TBL_BASE;
    }
    if (eunit_id >= SYS_AT_EUNIT_NUM_PER_CORE)
    {
        lchip = SYS_PP_BASE(lchip);
    }
    else
    {
        lchip = SYS_PP_BASE(lchip) + SYS_PP_NUM(lchip) / 2;
    }
    /*corss core dma info debug*/
    for (index = 0; index < SYS_AT_EUNIT_RING_NUM_PER_DMA_CTL; index++)
    {
        cmd = DRV_IOR(DmaStaticInfo_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index+tbl_base, DRV_CMD_PP_EN(cmd), &dma_info));
        if (CTC_IS_BIT_SET(ring_bmp, index))
        {
            cmd = DRV_IOR(DmaCtlTab_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, index+tbl_base, DRV_CMD_PP_EN(cmd), &ctl_tab));
            vld_num = GetDmaCtlTab(V, vldNum_f, &ctl_tab);
            ring_depth = GetDmaStaticInfo(V, ringDepth_f, &dma_info);
            mem_base = GetDmaStaticInfo(V, ringBase_f, &dma_info);
            mem_base <<= 4;
            if (eunit_id < SYS_AT_EUNIT_NUM_PER_CORE)
            {
                mem_base &= SYS_AT_EUNIT_REMOTE_MASK;
            }
            else
            {
                mem_base |= SYS_AT_EUNIT_REMOTE_BASE;
            }
            CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, mem_base, (uint32*)&ds_desc, sizeof(DsDesc_m)/sizeof(uint32)));
            data_base = GetDsDesc(V, memAddr_f, &ds_desc) << 4;
            if (eunit_id < SYS_AT_EUNIT_NUM_PER_CORE)
            {
                data_base &= SYS_AT_EUNIT_REMOTE_MASK;
            }
            else
            {
                data_base |= SYS_AT_EUNIT_REMOTE_BASE;
            }
            SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-2u%-4s%-10s%-10u%-7u%-7u0x%-13x  0x%-13x\n",
                index, "(R)", dma_ring_func[index], vld_num, dma_use_info.desc_cur_idx_cross_core[index], ring_depth, mem_base, data_base);
        }
    }
    return CTC_E_NONE;
}


int32
sys_at_eunit_show_dma_desc(uint8 lchip, uint8 eunit_id, uint8 chan_id, uint32 start_idx, uint32 end_idx)
{
    uint64 ring_addr = 0;
    uint32 ring_base_low28 = 0;
    uint32 ring_depth = 0;
    uint32 tbl_base = 0;
    uint32 cmd;
    uint32 index;
    DmaStaticInfo_m dma_info;
    DsDesc_m desc_mem;
    uint32 timestamp[2] = {0};
    uint64 tm_ns = 0;
    uint32 tm_s = 0;
    sys_eunit_dma_info_t dma_use_info;
    uint8 is_working = 0;

 	CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_MAX_VALUE_CHECK(chan_id, SYS_AT_EUNIT_RING_NUM_PER_DMA_CTL-1);
    CTC_MAX_VALUE_CHECK(start_idx, end_idx);

    SYS_AT_EUNIT_LCHIP_MAP(lchip, eunit_id);

    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }
    _sys_at_eunit_get_dma_info(lchip, eunit_id, &dma_use_info);
    SYS_AT_EUNIT_DMA_RESET_CHECK(lchip, dma_use_info.dma_sel);

    if(!CTC_IS_BIT_SET(dma_use_info.ring_bmp, chan_id))
    {
        return CTC_E_NONE;
    }
    
    if(SYS_AT_EUNIT_DMA0 == dma_use_info.dma_sel)
    {
        tbl_base = SYS_AT_EUNIT_DMA0_TBL_BASE;
    }
    else if (SYS_AT_EUNIT_DMA1 == dma_use_info.dma_sel)
    {
        tbl_base = SYS_AT_EUNIT_DMA1_TBL_BASE;
    }

    /* 1. get current chan Desc addr */
    cmd = DRV_IOR(DmaStaticInfo_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id+tbl_base, DRV_CMD_PP_EN(cmd), &dma_info));
    ring_base_low28 = GetDmaStaticInfo(V, ringBase_f, &dma_info);
    ring_addr = (ring_base_low28<<4);

    ring_depth = GetDmaStaticInfo(V, ringDepth_f, &dma_info);
    end_idx = (end_idx >= ring_depth ? (ring_depth-1) : end_idx);

    /* 2. dump desc */
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "P-Pause");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "DER-Data Error");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "D-Descriptor Done");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "ER-Total Error");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "CSize-Config Size");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "S-Descriptor SOP");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "RSize-Actual Size");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "T-Descriptor Timeout");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "M-Interrupt Mask");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-22s", "E-Descriptor EOP");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s", "DS-DataStruct(For Reg)");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-26s\n", "DeE-Descriptor Error");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " %-38s", "DAddr-Data Memory Address");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-27s\n", "V-Descriptor Valid");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-4s %-14s %-14s %-8s %-8s %-2s %-1s %-1s %-2s %-3s %-3s %-1s %-1s %-1s %-1s %-1s %-10s %-10s\n",
        "IDX", "DescAddr", "DAddr", "RSize", "CSize", "DS", "D", "V", "ER", "DER", "DeE", "T", "P", "M", "E", "S", "TS(ns)", "TS(s)");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "---------------------------------------------------------------------------------------------------\n");

    ring_addr += start_idx*sizeof(DsDesc_m);
    for (index = start_idx; index <= end_idx; index++)
    {
        sal_memset(&desc_mem, 0, sizeof(DsDesc_m));
        CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(eunit_id, ring_addr), (uint32*)&desc_mem, sizeof(DsDesc_m)/sizeof(uint32)));
        GetDsDesc(A, timestamp_f, &desc_mem, timestamp);
        
        tm_ns = timestamp[1];
        tm_ns = (tm_ns << 32);
        tm_ns |= timestamp[0];

        tm_s = tm_ns/1000000000;
        tm_ns = tm_ns - tm_s*1000000000;

        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-4d 0x%-12"PRIx64" 0x%-12x %-8d %-8d %-2d %-1d %-1d %-2d %-3d %-3d %-1d %-1d %-1d %-1d %-1d 0x%-8x 0x%-8x\n",
        index,
        ring_addr,
        GetDsDesc(V, memAddr_f, &desc_mem)<<4,
        GetDsDesc(V, realSize_f, &desc_mem),
        GetDsDesc(V, cfgSize_f, &desc_mem),
        GetDsDesc(V, dataStruct_f, &desc_mem),
        GetDsDesc(V, done_f, &desc_mem),
        GetDsDesc(V, valid_f, &desc_mem),
        GetDsDesc(V, error_f, &desc_mem),
        GetDsDesc(V, dataError_f, &desc_mem),
        GetDsDesc(V, descError_f, &desc_mem),
        GetDsDesc(V, u2_info_timeout_f, &desc_mem),
        GetDsDesc(V, pause_f, &desc_mem),
        GetDsDesc(V, intrMask_f, &desc_mem),
        GetDsDesc(V, u1_pkt_eop_f, &desc_mem),
        GetDsDesc(V, u1_pkt_sop_f, &desc_mem),
        (uint32)tm_ns,
        tm_s
        );
        ring_addr += sizeof(DsDesc_m);

    }

    return CTC_E_NONE;
}

/* len units: word */
int32
sys_at_eunit_show_mem(uint8 lchip, uint32 addr, uint32 len)
{
    uint32 index;
    uint8* data = NULL;
    uint32 line = 0;
    uint32 line_num = 0;
    uint32 word_idx = 0;
    uint8  line_word_num = 0;
    uint32 base = 0;
    int32 ret = CTC_E_NONE;
    host_type_t byte_order;

    if (!len)
    {
        return CTC_E_INVALID_PARAM;
    }
    CTC_MIN_VALUE_CHECK(addr, SYS_AT_EUNIT_MEM_BASE);
    /*CTC_MAX_VALUE_CHECK(addr+len*sizeof(uint32), SYS_AT_EUNIT_MEM_BASE+((SYS_AT_EUNIT_MEM_NUM*SYS_AT_EUNIT_MEM_SIZE)<<10));*/
    byte_order = drv_get_host_type(lchip);

    MALLOC_ZERO(MEM_SYSTEM_MODULE, data, len*sizeof(uint32));
    CTC_ERROR_GOTO(_sys_at_eunit_read_mem(lchip, SYS_AT_EUNIT_MEM_2_PCI_ADDR(0, addr), (uint32*)data, len),ret,error0);

    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"---------------------------------------------------------\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"Eunit memory dump\n");
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"---------------------------------------------------------\n");

    /* memory dump, 4 words per line */
    line_num = (len & 0x3) ? ((len >> 2) + 1) : (len >> 2);
    for (line = 0; line < line_num; line++)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"0x%08x: ",addr + line * 0x10);
        word_idx += 4;
        line_word_num = (word_idx > len) ? (4 - (word_idx - len)) : 4;
        for (index = 0; index < line_word_num; index++)
        {
            base = line * 16 + index * 4;
            
            if (byte_order == HOST_LE)
            {
                SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP," %02x%02x %02x%02x",\
                     data[base], data[base + 1], data[base + 2], data[base + 3]);
            }
            else
            {
                SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP," %02x%02x %02x%02x",\
                     data[base + 3], data[base + 2], data[base + 1], data[base]);
            }
        }
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"\n");
    }
    SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"---------------------------------------------------------\n");

error0:
    mem_free(data);
    return ret;
}

int32
sys_at_eunit_show_io_log(uint8 lchip, uint8 eunit_id, uint8 clear_en)
{
    uint32 offset = 0;
    uint8 i = 0;
    sys_eunit_cfg_cmd_t cfg_cmd = {0};
    uint32 log_buf[8] = {0};
    uint8 is_working = 0;

    CTC_MAX_VALUE_CHECK(eunit_id, MCHIP_CAP(SYS_CAP_EUNIT_NUM) - 1);
    CTC_ERROR_RETURN(sys_at_eunit_is_working(lchip, eunit_id, &is_working));
    if (!is_working)
    {
        return CTC_E_NOT_READY;
    }

    CTC_ERROR_RETURN(_sys_at_eunit_get_data_base(lchip, eunit_id, &offset));
    /* Get CMD Memory */
    CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
    cfg_cmd.done = 0;
    cfg_cmd.op = SYS_EUNIT_CFG_OP_GET;
    cfg_cmd.type = SYS_AT_EUNIT_IO_LOG;
    cfg_cmd.valid = 1;
    CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    CTC_ERROR_RETURN(_sys_at_eunit_cfg_op_finish(lchip, eunit_id, offset));
    CTC_ERROR_RETURN(_sys_at_eunit_read_mem(lchip, offset + sizeof(sys_eunit_cfg_cmd_t), log_buf, sizeof(log_buf) / 4));
    for (i = 0; i < 4; i++)
    {
        SYS_EUNIT_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"memMapLog[%d]: 0x%08x  0x%08x\n", i, log_buf[2*i], log_buf[2*i + 1]);
    }

    if (clear_en)
    {
        /* Get CMD Memory */
        CTC_ERROR_RETURN(_sys_at_eunit_get_empty_cmd(lchip, offset, &cfg_cmd));
        cfg_cmd.done = 0;
        cfg_cmd.op = SYS_EUNIT_CFG_OP_SET;
        cfg_cmd.type = SYS_AT_EUNIT_IO_LOG;
        cfg_cmd.valid = 1;
        CTC_ERROR_RETURN(_sys_at_eunit_write_mem(lchip, offset, (uint32 *)&cfg_cmd, sizeof(sys_eunit_cfg_cmd_t) / 4));
    }
    return CTC_E_NONE;
}

#endif
#endif


